3

如果我UIView.StringSize从诸如 a 之类的异步代码中运行Task.ContinueWith,它会以 aUIKitThreadAccessException开头,因为该方法以调用开始UIApplication.EnsureUIThread(MonoDevelop 中的“转到声明”;我不确定许可证是否允许我在此处发布)。

Task.Factory.StartNew(() => {
    // Blows up discretely...nothing written to application output.
    // Also blows up for UIViews that exist only in code (not rendered).
    SizeF textSize = someView.StringSize(someString, someFont, new SizeF(someView.Bounds.Width, float.MaxValue), UILineBreakMode.WordWrap);
    Console.WriteLine(textSize);
});

如果我将这个简化版本包含在 中InvokeOnMainThread,一切都很好,但我肯定有时间想在没有那个调用的情况下测量一些文本。同样,我完全理解异常的目的,并且在之前调用异步代码深处的东西时,它为我节省了很多麻烦,但在这种情况下,EnsureUIThread似乎没有必要使用这里。如果我只是简单地将该调用重申为对该NSString类的一次点击,它将很高兴地在 UI 线程之外运行。

Task.Factory.StartNew(() => {
    // Outputs expected size data: "{Width=##, Height=##}".
    using (NSString nssSomeString = new NSString(someString)) {
        SizeF textSize = nssSomeString.StringSize(someFont, new SizeF(someView.Bounds.Width, float.MaxValue), UILineBreakMode.WordWrap);
        Console.WriteLine(textSize);
    }
});

的代码UIView.StringSize似乎做了大致相同的NSString工作,并且似乎没有任何明显的面向 UI 线程的东西。我是否缺少需要从 UI 线程调用此版本的方法的内容?

编辑(2013-01-17):

向 Xamarin 提交了一个错误,只是为了查看他们的回复。听起来他们正在考虑将此方法标记为ThreadSafe.

4

2 回答 2

1

这是因为您UIView正在从未在其上创建的线程访问。由于您是NSString在后台线程中创建的,因此您的第二个示例将可以正常工作并被推荐。(虽然我认为你也不应该尝试someView.Bounds从后台线程访问)

我怀疑这也会起作用:

var bounds = someView.Bounds; //UI thread
Task.Factory.StartNew(() => {
    // Outputs expected size data: "{Width=##, Height=##}".
    using (UIView view = new UIView()) {
        SizeF textSize = view.StringSize(someString, someFont, new SizeF(bounds.Width, float.MaxValue), UILineBreakMode.WordWrap);
        Console.WriteLine(textSize);
    }
});

但我会坚持NSString

var bounds = someView.Bounds; //UI thread
Task.Factory.StartNew(() => {
    // Outputs expected size data: "{Width=##, Height=##}".
    using (NSString nssSomeString = new NSString(someString)) {
        SizeF textSize = nssSomeString.StringSize(someFont, new SizeF(bounds.Width, float.MaxValue), UILineBreakMode.WordWrap);
        Console.WriteLine(textSize);
    }
});
于 2013-01-17T18:50:40.727 回答
0

对方法的 UI 限制StringSize确实是不必要的。Xamarin 已经为 "v6.0.10+" 修复了这个问题

我们已经确定 DrawString (drawInRect:* selectors) 在其他线程中没有问题。StringSize 是该功能的一个子集,因此它应该是安全的。未来版本 (6.0.10+) 将被标记为 [ThreadSafe]。

在您针对更新版本进行编码之前,该NSString版本将正常工作。

于 2013-01-22T17:20:59.237 回答