If I run UIView.StringSize from within some async code like a Task.ContinueWith, it will blow up with a UIKitThreadAccessException because that method starts with a call to UIApplication.EnsureUIThread ("Go to declaration" in MonoDevelop; I’m not sure the license allows me to post it here).
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);
});
If I wrap this simplified version in InvokeOnMainThread, all is well, but I definitely have times when I want to measure some text without that call. As well, I fully understand the exception’s purpose and it has saved me a bunch of hassle when called something deep within async code before, but in this case the use of EnsureUIThread here seems unnecessary. If I simply restate that call as a hit on the NSString class, it will happily run outside the UI thread.
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);
}
});
The code for UIView.StringSize appears to do roughly the same NSString work and there doesn’t appear to be anything blatantly UI-thread-oriented. Is there something I am missing that would require this version of the method to be called from the UI thread?
Edit (2013-01-17):
I filed a bug with Xamarin just to see their response. It sounds like they are looking into marking this method as ThreadSafe.
The UI restriction on the
StringSizemethod is indeed unnecessary. Xamarin has already fixed this for “v6.0.10+”.Until you are coding against the updated version, the
NSStringversion will work just fine.