Note that there are some explanatory texts on larger screens.

plurals
  1. POUIStringDrawing methods don't seem to be thread safe in iOS 6
    text
    copied!<p>Using any UIStringDrawing methods on two threads simultaneously causes a crash. My understanding was that all UIStringDrawing methods were thread safe from iOS 4.0.</p> <p>This code (that does nothing of any use) demonstrates the problem:</p> <pre><code>dispatch_queue_t queue = dispatch_queue_create("com.queue", NULL); for (int i = 0; i &lt; 10000; i++) { dispatch_async(queue, ^{ NSString *string = @"My string"; CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]]; }); } for (int i = 0; i &lt; 10000; i++) { NSString *string = @"My string"; CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]]; } dispatch_release(queue); </code></pre> <p>The app crashes after a few iterations of the loops with the following backtrace:</p> <pre><code>* thread #1: tid = 0x2403, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8) frame #0: 0x00ad40c8 frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 90 frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 10 frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246 frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200 frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66 frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58 frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46 frame #8: 0x00060ca8 myApp`-[TAViewController drawingTest] + 216 at TAViewController.m:157 frame #9: 0x38da1e66 Foundation`__NSFireDelayedPerform + 450 frame #10: 0x3aa47856 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14 frame #11: 0x3aa47502 CoreFoundation`__CFRunLoopDoTimer + 274 frame #12: 0x3aa46176 CoreFoundation`__CFRunLoopRun + 1230 frame #13: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356 frame #14: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104 frame #15: 0x3a8a433a GraphicsServices`GSEventRunModal + 74 frame #16: 0x3622c288 UIKit`UIApplicationMain + 1120 frame #17: 0x0005f08c myApp`main + 96 at main.m:16 thread #5: tid = 0x2a03, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8) frame #0: 0x00ad40c8 frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 90 frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 10 frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246 frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200 frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66 frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58 frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46 frame #8: 0x00060d5c myApp`__31-[TAViewController drawingTest]_block_invoke_0 + 116 at TAViewController.m:150 frame #9: 0x339f0792 libdispatch.dylib`_dispatch_call_block_and_release + 10 frame #10: 0x339f3b3a libdispatch.dylib`_dispatch_queue_drain + 142 frame #11: 0x339f167c libdispatch.dylib`_dispatch_queue_invoke + 44 frame #12: 0x339f4612 libdispatch.dylib`_dispatch_root_queue_drain + 210 frame #13: 0x339f47d8 libdispatch.dylib`_dispatch_worker_thread2 + 92 frame #14: 0x37f957f0 libsystem_c.dylib`_pthread_wqthread + 360 frame #15: 0x37f95684 libsystem_c.dylib`start_wqthread + 8 </code></pre> <p>My understanding was that UIStringDrawing methods were thread safe from iOS 4. I expect that these loops should complete with no errors.</p> <p>The crash occurs when running on an iPhone running iOS 6 (tested on iPhone 5) but does NOT occur when running on an iPhone running iOS 5 (tested on iPhone 4) or the simulator (tested with iOS 6).</p> <p>I have implemented what I thought was a fix by serialising any draw calls using CGD:</p> <pre><code>- (void)serialiseDrawing:(void (^)())block { dispatch_sync(self.serialDrawingQueue, block); } - (dispatch_queue_t)serialDrawingQueue { if (_serialDrawingQueue == NULL) _serialDrawingQueue = dispatch_queue_create("com.myApp.SerialDrawQueue", NULL); return _serialDrawingQueue; } </code></pre> <p>...and wrapping every draw call like this:</p> <pre><code>__block CGSize labelSize = CGSizeZero; [[TAUtils sharedUtils] serialiseDrawing:^{ labelSize = [label.text sizeWithFont:label.font]; }]; </code></pre> <p>This seems to have improved things a bit (all my UIStringDrawing calls happen on one thread). But it will still crash at times with a backtrace like this:</p> <pre><code>Exception Type: EXC_CRASH (SIGSEGV) Exception Codes: 0x0000000000000000, 0x0000000000000000 Crashed Thread: 0 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x3a28ee80 semaphore_wait_trap + 8 1 libdispatch.dylib 0x32851e90 _dispatch_thread_semaphore_wait + 8 2 libdispatch.dylib 0x32850680 _dispatch_barrier_sync_f_slow + 100 3 myApp 0x000c4330 -[TAUtils serialiseDrawing:] (TAUtils.m:305) 4 myApp 0x000edfd4 -[TAOmniBar updateLabel] (TAOmniBar.m:394) 5 myApp 0x000ee8d6 -[TAOmniBar handleNotification:] (TAOmniBar.m:461) 6 CoreFoundation 0x39820346 _CFXNotificationPost + 1418 7 Foundation 0x37b5838a -[NSNotificationCenter postNotificationName:object:userInfo:] + 66 8 Foundation 0x37b5be9a -[NSNotificationCenter postNotificationName:object:] + 26 9 myApp 0x000f369a -[TAMyViewController update] (TAMyViewController.m:1308) 10 GLKit 0x328383ce -[GLKViewController _updateAndDraw] + 270 11 QuartzCore 0x39ffd77c CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) + 156 12 QuartzCore 0x39ffd6d4 CA::Display::IOMFBDisplayLink::callback(__IOMobileFramebuffer*, unsigned long long, unsigned long long, unsigned long long, void*) + 60 13 IOMobileFramebuffer 0x31221fd4 IOMobileFramebufferVsyncNotifyFunc + 152 14 IOKit 0x39f7c5aa IODispatchCalloutFromCFMessage + 190 15 CoreFoundation 0x39899888 __CFMachPortPerform + 116 16 CoreFoundation 0x398a43e4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32 17 CoreFoundation 0x398a4386 __CFRunLoopDoSource1 + 134 18 CoreFoundation 0x398a320a __CFRunLoopRun + 1378 19 CoreFoundation 0x39816238 CFRunLoopRunSpecific + 352 20 CoreFoundation 0x398160c4 CFRunLoopRunInMode + 100 21 GraphicsServices 0x39701336 GSEventRunModal + 70 22 UIKit 0x35089284 UIApplicationMain + 1116 23 myApp 0x000b806e main (main.m:16) 24 myApp 0x000b8024 start + 36 Thread 7 name: Dispatch queue: com.myApp.SerialDrawQueue Thread 7: 0 WebCore 0x35a21410 WebCore::FontFallbackList::invalidate(WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 156 1 WebCore 0x35a2124e WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 86 2 WebCore 0x35a211ee WebCore::Font::Font(WebCore::FontPlatformData const&amp;, WTF::PassRefPtr&lt;WebCore::FontSelector&gt;) + 6 3 WebKit 0x37d6068a rendererForFont(__GSFont*) + 242 4 WebKit 0x37d61796 -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:drawUnderline:] + 198 5 WebKit 0x37d616bc -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:] + 84 6 WebKit 0x37d6165e -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:] + 82 7 WebKit 0x37d61602 -[NSString(WebStringDrawing) _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:] + 78 8 UIKit 0x35041960 -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] + 172 9 UIKit 0x3507de1e -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:fontSize:lineBreakMode:baselineAdjustment:includeEmoji:] + 358 10 UIKit 0x3507dca4 -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:fontSize:lineBreakMode:baselineAdjustment:] + 68 11 myApp 0x000d3300 -[TALabelManager textureCGImageForString:] (TALabelManager.m:859) 12 myApp 0x000d350a __39-[TALabelManager textureDataForString:]_block_invoke_0 (TALabelManager.m:875) 13 libdispatch.dylib 0x3284d5d8 _dispatch_client_callout + 20 14 libdispatch.dylib 0x3285080a _dispatch_barrier_sync_f_invoke + 22 15 myApp 0x000c4330 -[TAUtils serialiseDrawing:] (TAUtils.m:305) 16 myApp 0x000d3420 -[TALabelManager textureDataForString:] (TALabelManager.m:873) 17 myApp 0x000d0dde __block_global_0 (TALabelManager.m:516) 18 libdispatch.dylib 0x3284d790 _dispatch_call_block_and_release + 8 19 libdispatch.dylib 0x32850b36 _dispatch_queue_drain + 138 20 libdispatch.dylib 0x3284e678 _dispatch_queue_invoke + 40 21 libdispatch.dylib 0x32851610 _dispatch_root_queue_drain + 208 22 libdispatch.dylib 0x328517d4 _dispatch_worker_thread2 + 88 23 libsystem_c.dylib 0x36df27ee _pthread_wqthread + 358 24 libsystem_c.dylib 0x36df2680 start_wqthread + 4 </code></pre> <p>I apologise for the long question but this is a serious problem for me and would really appreciate any help.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload