为什么UIView.StringSize需要在UI线程上运行?

时间:2013-01-17 18:36:20

标签: xamarin.ios

如果我从UIView.StringSize之类的某些异步代码中运行Task.ContinueWith,那么它会以UIKitThreadAccessException爆炸,因为该方法首先调用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中,一切都很好,但我确实有时候想要在没有该调用的情况下测量一些文本。同样,我完全理解exception's purpose并且在以前在异步代码中深度调用某些内容时为我节省了一些麻烦,但在这种情况下,在这里使用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):

filed a bug with Xamarin只是为了看到他们的回应。听起来他们正在考虑将此方法标记为ThreadSafe

2 个答案:

答案 0 :(得分: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);
    }
});

答案 1 :(得分:0)

StringSize方法的UI限制确实是不必要的。 Xamarin已经fixed this for "v6.0.10+"

  

我们已经认识到DrawString(drawInRect:* selectors)很好   其他线程。 StringSize是该功能的子集,因此它应该是安全的。   未来版本(6.0.10+)将标记为[ThreadSafe]。

在您对更新版本进行编码之前,NSString版本可以正常运行。