Bug 58832 - NSString.DrawString(CGPoint,UIStringAttributes) incorrectly throws when called on background thread
Summary: NSString.DrawString(CGPoint,UIStringAttributes) incorrectly throws when calle...
Status: CONFIRMED
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll (show other bugs)
Version: XI 10.99 (xcode9)
Hardware: PC Mac OS
: --- normal
Target Milestone: Future Cycle (TBD)
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-08-16 23:12 UTC by Larry O'Brien
Modified: 2017-09-22 14:47 UTC (History)
5 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Application that throws (WatermarkPage.cs line 59) (234.89 KB, application/zip)
2017-08-16 23:12 UTC, Larry O'Brien
Details

Description Larry O'Brien 2017-08-16 23:12:38 UTC
Created attachment 24258 [details]
Application that throws (WatermarkPage.cs line 59)

I believe that `NSString.DrawString(CGPoint,UIStringAttributes)` should be callable from a background thread. I think the method is defined as an extension method in the class `NSStringDrawing`.

The attached project draws strings on a PdfPage. It is a port of Apple's sample: 

https://developer.apple.com/sample-code/wwdc/2017/Document-Watermark.zip

In Swift, working code looks like:

        let string: NSString = "U s e r   3 1 4 1 5 9"
        let attributes = [
            NSAttributedStringKey.foregroundColor: UIColor(colorLiteralRed: 0.5, green: 0.5, blue: 0.5, alpha: 0.5),
            NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 64)
        ]

        string.draw(at: CGPoint(x:250, y:40), withAttributes: attributes)

In C#, the straight-across port would seem to be: 

            var text = new NSString("Confidential");
            var attributes = new UIStringAttributes()
            {
                ForegroundColor = UIColor.FromRGBA(255, 0, 0, 125),
                Font = UIFont.BoldSystemFontOfSize(64)
            };

            text.DrawString(new CGPoint(250, 40), attributes);
            

But, when run, the `DrawString(CGPoint,UIAttributes)` call raises a `UIKitThreadAccessException`. If you wrap the call to `DrawString` in either a `InvokeOnMainThread` or `DispatchQueue.MainQueue.DispatchSync` call, the text is not written to the context (even if you block). 

You can successfully draw an attributed string if you change the code to:

			var attributes = new UIStringAttributes()
			{
				ForegroundColor = UIColor.FromRGBA(255, 0, 0, 125),
				Font = UIFont.BoldSystemFontOfSize(64)
			};

			var text = new NSAttributedString("Confidential", attributes);
           
			text.DrawString(new CGPoint(250, 40));

Also, NSString.DrawString(CGPoint,Font) works fine on a background thread:

			var t2 = new NSString("This works");
			t2.DrawString(new CGPoint(250, 90), UIFont.BoldSystemFontOfSize(30));

The attached project demonstrates the problem. WatermarkPage.cs, line 59, if left uncommented, throws. Comment it out and the program runs. 

---

=== Visual Studio Community 2017 for Mac (Preview) ===

Version 7.1 Preview (7.1 build 1267)
Installation UUID: 6b94f136-026d-4a5a-bf6d-af2c0d8dc019
Runtime:
	Mono 5.2.0.196 (2017-04/478c04a) (64-bit)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 502000196

=== NuGet ===

Version: 4.3.0.2418

=== .NET Core ===

Runtime: Not installed
SDK: Not installed
MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/5.2.0/lib/mono/msbuild/15.0/bin/Sdks

=== Xamarin.Profiler ===

Version: 1.4.0
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Apple Developer Tools ===

Xcode 9.0 (13226.5)
Build 9M202q

=== Xamarin.iOS ===

Version: 10.99.3.38 (Visual Studio Community)
Hash: 4e3cad4
Branch: xcode9
Build date: 2017-08-11 10:58:25-1000

=== Xamarin.Android ===

Version: 7.3.1.2 (Visual Studio Community)
Android SDK: /Users/larryobrien/Library/Developer/Xamarin/android-sdk-macosx
	Supported Android versions:
		2.3   (API level 10)
		4.0.3 (API level 15)
		4.4   (API level 19)
		5.0   (API level 21)
		5.1   (API level 22)
		6.0   (API level 23)

SDK Tools Version: 25.2.5
SDK Platform Tools Version: 25.0.5
SDK Build Tools Version: 25.0.3

Java SDK: /usr
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

=== Xamarin.Mac ===

Version: 3.99.3.38 (Visual Studio Community)

=== Xamarin Inspector ===

Version: 1.3.0-alpha2
Hash: fa030e0
Branch: master
Build date: Thu, 01 Jun 2017 20:55:26 GMT
Client compatibility: 1

=== Build Information ===

Release ID: 701001267
Git revision: 342f47be42098b95880cf4c6d957719b5fef53e3
Build date: 2017-07-12 17:43:22-04
Xamarin addins: e513cc1830b4daa75f67c608e2c722e811b23ab2
Build lane: monodevelop-lion-d15-3-xcode9

=== Operating System ===

Mac OS X 10.12.6
Darwin 16.7.0 Darwin Kernel Version 16.7.0
    Thu Jun 15 17:36:27 PDT 2017
    root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
Comment 1 Alex Soto [MSFT] 2017-08-17 02:08:43 UTC
I am not entirely sure on this one the API used here is:

https://developer.apple.com/documentation/foundation/nsstring/1533109-drawatpoint

the documentation just states this:

> There must be either a focused view or an active graphics context when you call this method.

Which could imply it is thread safe, the only requirement is a GCContext or a focused view according to it.

@rolf / @sebastien thoughts?

Moving to need awaiting Rolf's or Sebastien's input
Comment 2 Rolf Bjarne Kvinge [MSFT] 2017-08-17 06:41:56 UTC
I think it should be thread safe, based on the documentation.

Also Xcode 9 added the same ui thread check we have, which means that if the Xcode sample is working fine in Xcode 9, it implies the API is safe to use.
Comment 3 Sebastien Pouliot 2017-08-17 13:05:57 UTC
> Also Xcode 9 added the same ui thread check we have

Is it enabled by default ?
I wanted to look at the option but have not gotten around to do it yet :(
Comment 4 Rolf Bjarne Kvinge [MSFT] 2017-08-17 13:23:01 UTC
> > Also Xcode 9 added the same ui thread check we have
> 
> Is it enabled by default ?
> I wanted to look at the option but have not gotten around to do it yet :(

Yes, it's enabled by default when debugging with Xcode (https://developer.apple.com/documentation/code_diagnostics/main_thread_checker).(In reply to Sebastien Pouliot from comment #3)
Comment 5 Manuel de la Peña 2017-09-22 14:47:01 UTC
After a conversation with @sebastien, setting to confirmed.

Note You need to log in before you can comment on or make changes to this bug.