Hello, fellow cocoa devs.
I'm running down the most common crasher we're seeing in OmniPlan-2.0 under
Lion and running onto some grief with NSSpellChecker/NSTextView. We have a
fairly complex outline view that is backed by many text storages and the field
editor is asked to do a lot. When editing a row, we create a text storage for
that row's contents, then insert a field editor into the view hierarchy and
call -replaceTextStorage: on its layout manager with our freshly-minted text
storage.
If I enable “Correct Spelling Automatically”, create a new task and title it
"Hello htere" [sic], spell checking is performed asynchronously on the main
thread and the NSSpellChecker shows a correctionIndicator
#0 0x00007fff8c295a5b in -[NSSpellChecker
showCorrectionIndicatorOfType:primaryString:alternativeStrings:forStringInRect:view:completionHandler:]
()
#1 0x00007fff8bf12cef in -[NSTextView
handleTextCheckingResults:forRange:types:options:orthography:wordCount:] ()
#2 0x00007fff8bf11565 in -[NSTextView
_handleTextCheckingResults:sequenceNumber:forRange:types:options:orthography:wordCount:applyNow:]
()
#3 0x00007fff8bf113e6 in __-[NSTextView
checkTextInRange:types:options:]_block_invoke_2 ()
#4 0x00007fff896a6ecc in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ ()
#5 0x00007fff8965efa2 in __CFRunLoopDoBlocks ()
#6 0x00007fff89686f07 in __CFRunLoopRun ()
…
If I hit return, the default correction is selected and I infer that the
completionHandler is enqueued on the main queue. However, our custom
implementation of -insertNewline: will also end editing on the current row,
create a new item with another text storage behind it, and tell the field
editor's layout manager to replaceTextStorage: with that new row's text
storage. After we return to the run loop, an NSPortMessage happens to be
received by another object, and that object calls [NSApp
nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast]
inMode:NSEventTrackingRunLoopMode dequeue:NO], which will again fire the run
loop. This causes the the main queue to fire its pending blocks, and thus the
NSTextView's text checking handler's completionHandler is run and raises an
exception:
#13 0x00007fff896f1ab4 in +[NSException raise:format:] ()
#14 0x00007fff896af87e in -[__NSCFString characterAtIndex:] ()
#15 0x00007fff8bf17e76 in -[NSAttributedString(NSAttributedStringKitAdditions)
doubleClickAtIndex:inRange:] ()
#16 0x00007fff8bf17de7 in -[NSAttributedString(NSAttributedStringKitAdditions)
doubleClickAtIndex:] ()
#17 0x00007fff8bf17da4 in -[NSTextView _doubleClickAtIndex:limitedRangeOK:] ()
#18 0x00007fff8c304d61 in __-[NSTextView
handleTextCheckingResults:forRange:types:options:orthography:wordCount:]_block_invoke_2
()
#19 0x00007fff8dbdf90a in _dispatch_call_block_and_release ()
#20 0x00007fff8dbe177a in _dispatch_main_queue_callback_4CF ()
#21 0x00007fff89686ddc in __CFRunLoopRun ()
#22 0x00007fff896863e6 in CFRunLoopRunSpecific ()
#23 0x00007fff90e5c697 in RunCurrentEventLoopInMode ()
#24 0x00007fff90e63db9 in ReceiveNextEventCommon ()
#25 0x00007fff90e63c46 in BlockUntilNextEventMatchingListInMode ()
#26 0x00007fff8bd2baf5 in _DPSNextEvent ()
#27 0x00007fff8bd2b3fc in -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:] ()
…
Here, this problem occurs because the field editor's new NSTextStorage is
shorter now (having a default task title of something like “Task 2”). The
completion handler appears to be hanging on to the range of the
NSTextCheckingResult it's handling, (NSRange){6, 5}. The exception we get is:
---------------------------
Mask: 0x00000001
Name: NSRangeException
Reason: -[__NSCFString characterAtIndex:]: Range or index out of bounds
Info:
Because we regard an unhandled exception in a place like this as a potential
data corruptor, we immediately crash on purpose and hope the user will send in
a crash report with a backtrace to the scene of the crime.
It just looks to me like it's unsafe to change the text storage backing the
field editor unless you can be sure that there are no text checking completion
blocks hanging around on the main dispatch queue. I don't believe there's any
API or trick to get the spell checker to wrap up its text checking now,
synchronously. Subclassing [NSTextView
handleTextCheckingResults:forRange:types:options:orthography:wordCount:] in our
field editor would be pretty onerous; it's a very complicated method.
Your thoughts would be very welcome. I'm happy to provide more information of
course, but I've got over half a million lines of .m files here and I'm trying
to narrow the scope of the problem suitably. Kyle is currently across the hall
striving to reproduce this problem in a smaller, Radar-compatible sample
project.
Thanks!
-Tom_______________________________________________
Cocoa-dev mailing list ([email protected])
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]