Goal
Use NSPasteboard's canReadObjectForClasses:options: within a custom toolbar item's - (void)validate to determine the toolbar's enabled state.
Issue
When using NSPasteboard pasteboardWithName and then calling canReadObjectForClasses:options: within the toolbar item's - (void)validate method it causes the Leak Profiler to detect leaks.
Stack Trace of Detected Leak
0 libsystem_malloc.dylib _malloc_zone_calloc
1 Foundation -[NSConcreteMapTable initWithKeyOptions:valueOptions:capacity:]
2 AppKit -[_NSPasteboardTypeCache init]
3 AppKit -[NSPasteboard _updateTypeCacheIfNeeded]
4 AppKit -[NSPasteboard _cachedTypeNameUnion]
5 AppKit -[NSPasteboard(NSTypeConversion) _conformingTypes]
6 AppKit -[NSPasteboard canReadObjectForClasses:options:]
7 testingPasteboardLeak -[TestToolbarItem validate] ~/Documents/Code/tests/testingPasteboardLeak/testingPasteboardLeak/TestToolbarItem.m:14
8 AppKit -[NSToolbarItemViewer configureForLayoutInDisplayMode:andSizeMode:inToolbarView:]
9 AppKit -[NSToolbarView _layoutDirtyItemViewersAndTileToolbar]
10 AppKit -[NSToolbarView _syncItemSetAndUpdateItemViewersWithSEL:setNeedsModeConfiguration:sizeToFit:setNeedsDisplay:updateKeyLoop:]
11 AppKit -[NSToolbarView _noteToolbarLayoutChanged]
12 AppKit -[NSView _setWindow:]
13 AppKit -[NSView addSubview:]
14 AppKit -[NSThemeFrame addTitlebarSubview:]
15 AppKit -[NSThemeFrame _showHideToolbar:resizeWindow:animate:]
16 AppKit -[NSWindow _showToolbar:animate:]
17 AppKit -[NSToolbar _show:animate:]
18 CoreFoundation -[NSSet makeObjectsPerformSelector:]
19 AppKit -[NSIBObjectData nibInstantiateWithOwner:options:topLevelObjects:]
20 AppKit -[NSNib _instantiateNibWithExternalNameTable:options:]
21 AppKit -[NSNib _instantiateWithOwner:options:topLevelObjects:]
22 AppKit -[NSStoryboard _instantiateControllerWithIdentifier:creator:storyboardSegueTemplate:sender:]
23 AppKit NSApplicationMain
24 libdyld.dylib start
Example Code
Custom toolbar item's validate method:
- (void)validate {
NSPasteboard *myPasteboard = [NSPasteboard pasteboardWithName:#"TestPasteboardName"];
BOOL isValid = [myPasteboard canReadObjectForClasses:#[[NSString class], [NSURL class]] options:nil];
}
WindowController which is delegate to the toolbar:
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)aToolbar {
return #[#"test"];
}
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)aToolbar {
return #[#"test"];
}
- (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
TestToolbarItem *item = [[TestToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
[item setTitle:#"TestToolbar"];
return item;
}
What I've tried so far
Use NSPasteboard releaseGlobally when closing the window -- leak still present.
Wrap the pasteboard check in #autoreleasepool -- leak still present.
Using releaseGlobally directly after the pasteboard check gets rid of the leak, but obviously also clears out the pasteboard.
Question
Is there a way to use a private pasteboard's canReadObjectForClasses:options: within a custom toolbar item's validate method without causing a leak?
Related
I am getting the following crash in HockeyApp more seriously in iOS10. Please find the crash log as given below.
Thread 4 Crashed:
0 libobjc.A.dylib 0x0000000187242f30 objc_msgSend + 16
1 UIKit 0x000000018e86e914 -[UIWebDocumentView _updateSubviewCaches] + 36
2 UIKit 0x000000018e69093c -[UIWebDocumentView subviews] + 88
3 UIKit 0x000000018e941bd4 -[UIView(CALayerDelegate) _wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:] + 68
4 UIKit 0x000000018e63d770 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1248
5 QuartzCore 0x000000018bb0640c -[CALayer layoutSublayers] + 144
6 QuartzCore 0x000000018bafb0e8 CA::Layer::layout_if_needed(CA::Transaction*) + 288
7 QuartzCore 0x000000018bafafa8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 28
8 QuartzCore 0x000000018ba77c64 CA::Context::commit_transaction(CA::Transaction*) + 248
9 QuartzCore 0x000000018ba9f0d0 CA::Transaction::commit() + 508
10 QuartzCore 0x000000018ba9faf0 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 116
11 CoreFoundation 0x00000001887a57dc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 28
12 CoreFoundation 0x00000001887a340c __CFRunLoopDoObservers + 368
13 CoreFoundation 0x00000001886d2068 CFRunLoopRunSpecific + 472
14 WebCore 0x000000018d273a2c RunWebThread(void*) + 452
15 libsystem_pthread.dylib 0x000000018788b860 _pthread_body + 236
16 libsystem_pthread.dylib 0x000000018788b770 _pthread_start + 280
17 libsystem_pthread.dylib 0x0000000187888dbc thread_start + 0
Any idea what is going on here ?
Seems like the following crash groups are also related.
Crash Group 1
[UIWebBrowserView _collectAdditionalSubviews]
objc_msgSend() selector name: autorelease
Crash Group 2
[UIWebDocumentView subviews]
objc_msgSend() selector name: arrayByAddingObjectsFromArray:
I am answering to my own question, since I am able to replicate this issue and found the root cause.
Please note the following.
1. I am using a UIWebView. First of all, this is not recommended.
2. The following way of implementation causes this issue. I am writing pseudo-code here to demonstrate the problem.
#implementation MyViewController
- (void)loadView {
//creating UIWebView Here
self.webView = [[UIWebView alloc] initWithFrame:_some_frame];
//setting the web view properties here.
//Adding to the view
[self.view addSubView: self.webView];
[self populateWebView];
}
- (void) populateWebView {
[self.webView loadHTMLString:_some_html
baseURL:[NSURL fileURLWithPath:_some_path]];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.webView) {
//The following two lines causing this issue.
self.webView.scrollView.contentInset = _some_insets;
self.webView.scrollView.scrollIndicatorInsets = _some_insets;
}
}
#end
3. The solution is given below.
#implementation MyViewController
- (void)loadView {
//creating UIWebView Here
self.webView = [[UIWebView alloc] initWithFrame:_some_frame];
//setting the web view properties here.
//Adding to the view
[self.view addSubView: self.webView];
[self populateWebView];
}
- (void) populateWebView {
[self.webView loadHTMLString:_some_html
baseURL:[NSURL fileURLWithPath:_some_path]];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webView.scrollView.contentInset = _some_insets;
webView.scrollView.scrollIndicatorInsets = _some_insets;
}
#end
In my actual code, I was using a custom WebView class here by subclassing the UIWebView. Not think that will create some issue. The root cause is setting the "contentInset" and "scrollIndicatorInsets" in viewDidLayoutSubviews which is not a good idea. When I put the break points, "viewDidLayoutSubviews" called several times and eventually App crashes.
As a solution I moved the following part of the code into "webViewDidFinishLoad" which will call only when the WebView is ready after finished loading. So it makes sense to add this code under this delegate method.
webView.scrollView.contentInset = _some_insets;
webView.scrollView.scrollIndicatorInsets = _some_insets;
I'm seeing this crash happen very randomly:
Fatal Exception: NSInvalidArgumentException
*** setObjectForKey: object cannot be nil (key: NSViewController-Qmf-WE-Bmb)
0 CoreFoundation 0x7fff95e504da __exceptionPreprocess
1 libobjc.A.dylib 0x7fff923eef7e objc_exception_throw
2 CoreFoundation 0x7fff95d4a414 -[__NSDictionaryM setObject:forKey:]
3 AppKit 0x7fff9857f917 -[NSStoryboard nibForControllerWithIdentifier:]
4 AppKit 0x7fff9857fc11 -[NSStoryboard instantiateControllerWithIdentifier:]
5 AppKit 0x7fff982e733b -[NSStoryboardSegueTemplate _perform:]
6 AppKit 0x7fff983345d7 -[NSViewController performSegueWithIdentifier:sender:]
7 libdispatch.dylib 0x7fff8e5cc93d _dispatch_call_block_and_release
8 libdispatch.dylib 0x7fff8e5c140b _dispatch_client_callout
9 libdispatch.dylib 0x7fff8e5d4c1c _dispatch_main_queue_callback_4CF
10 CoreFoundation 0x7fff95e059e9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
11 CoreFoundation 0x7fff95dc48dd __CFRunLoopRun
12 CoreFoundation 0x7fff95dc3ed8 CFRunLoopRunSpecific
13 HIToolbox 0x7fff99b4b935 RunCurrentEventLoopInMode
14 HIToolbox 0x7fff99b4b76f ReceiveNextEventCommon
15 HIToolbox 0x7fff99b4b5af _BlockUntilNextEventMatchingListInModeWithFilter
16 AppKit 0x7fff97e3bdf6 _DPSNextEvent
17 AppKit 0x7fff97e3b226 -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
18 AppKit 0x7fff97e2fd80 -[NSApplication run]
19 AppKit 0x7fff97df9368 NSApplicationMain
20 libdyld.dylib 0x7fff8c6875ad start
I've verified that the segue identifier is correct and that the storyboard exists and contains the segue. I've also verified that there is a view controller with ID: Qmf-WE-Bmb.
Any clues why this would happen? Does this mean the source VC is deallocated or that its failing to load the destination VC?
In case anyone hits the same issue, I circumvented the crash by replacing performSegueWithIdentifier: with a custom function on my base controller:
- (void)performManualSegueWithControllerID:(NSString *)identifier {
if ([NSThread isMainThread]) {
NSViewController *controller = [self.storyboard instantiateControllerWithIdentifier:identifier];
if (controller) {
MyCustomAnimator *animator = [[MyCustomAnimator alloc] init];
[animator setAnimateVertically:NO];
[self prepareForManualSegueToController:controller];
[self presentViewController:controller animator:animator];
} else {
// Some Error
}
} else {
[self performSelectorOnMainThread:#selector(performManualSegueWithControllerID:)
withObject:identifier
waitUntilDone:NO];
}
}
- (void)prepareForManualSegueToController:(NSViewController *)controller {
}
UPDATE 2
My app is crashing when presenting it modally after a user taps a button in ViewController1. In my storyboard, I have a standard present modally segue set to pop up the UINavController/UITableViewController containing the UISearchBar. That's failing every time.
However, in my AppDelegate, if I set the window's rootViewController to the same UINavController/UITableViewController, everything works as expected.
For some reason transitioning via segue and then acting the UISearchBar is causing the crash.
UPDATE 1
I'm now receiving the following error when tapping one letter:
2015-02-03 12:23:35.262 Afar D[28348:2740681] -[NSNull length]: unrecognized selector sent to instance 0x10e352ce0
2015-02-03 12:23:40.313 Afar D[28348:2740681] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x10e352ce0'
*** First throw call stack:
(
0 CoreFoundation 0x000000010e0a9f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010dd42bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010e0b104d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010e00927c ___forwarding___ + 988
4 CoreFoundation 0x000000010e008e18 _CF_forwarding_prep_0 + 120
5 CoreFoundation 0x000000010df89a7b CFStringCompareWithOptionsAndLocale + 219
6 Foundation 0x000000010d6822b7 -[NSString compare:options:range:] + 29
7 UIKit 0x000000010c5f53b4 -[UIPhysicalKeyboardEvent _matchesKeyCommand:] + 224
8 UIKit 0x000000010c53c12e -[UIResponder(Internal) _keyCommandForEvent:] + 285
9 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
10 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
11 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
12 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
13 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
14 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
15 UIKit 0x000000010c53c197 -[UIResponder(Internal) _keyCommandForEvent:] + 390
16 UIKit 0x000000010c3d8f0a -[UIApplication _handleKeyUIEvent:] + 126
17 UIKit 0x000000010c5c7fcc -[UIKeyboardImpl _handleKeyEvent:executionContext:] + 66
18 UIKit 0x000000010c75bbb7 -[UIKeyboardLayoutStar completeRetestForTouchUp:timestamp:interval:executionContext:] + 3611
19 UIKit 0x000000010c75a8e5 -[UIKeyboardLayoutStar touchUp:executionContext:] + 1374
20 UIKit 0x000000010c5d531b __28-[UIKeyboardLayout touchUp:]_block_invoke + 242
21 UIKit 0x000000010cb23914 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 332
22 UIKit 0x000000010c5d521c -[UIKeyboardLayout touchUp:] + 252
23 UIKit 0x000000010c5d5cc6 -[UIKeyboardLayout touchesEnded:withEvent:] + 319
24 UIKit 0x000000010c40b308 -[UIWindow _sendTouchesForEvent:] + 735
25 UIKit 0x000000010c40bc33 -[UIWindow sendEvent:] + 683
26 UIKit 0x000000010c3d89b1 -[UIApplication sendEvent:] + 246
27 UIKit 0x000000010c3e5a7d _UIApplicationHandleEventFromQueueEvent + 17370
28 UIKit 0x000000010c3c1103 _UIApplicationHandleEventQueue + 1961
29 CoreFoundation 0x000000010dfdf551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
30 CoreFoundation 0x000000010dfd541d __CFRunLoopDoSources0 + 269
31 CoreFoundation 0x000000010dfd4a54 __CFRunLoopRun + 868
32 CoreFoundation 0x000000010dfd4486 CFRunLoopRunSpecific + 470
33 GraphicsServices 0x000000010fc109f0 GSEventRunModal + 161
34 UIKit 0x000000010c3c4420 UIApplicationMain + 1282
35 My App 0x000000010a5e1c63 main + 115
36 libdyld.dylib 0x000000010e75a145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I'm using iOS8's new UISearchController to manage a UISearchBar for filtering data in a table. If I activate the UISearchBar, the app crashes as soon as I type the first letter (Interestingly, the on-screen keyboard doesn't appear in the Simulator, but I don't think that's related).
In order to narrow things down, I've commented almost everything out of my UIViewController so that the UITableView renders nothing. I've implemented UISearchControllerDelegate and UISearchBarDelegate just so I can log when each method gets called. However, after typing the first letter, I receive no console messages. I don't even know where I could set a breakpoint.
Here's the crash I get:
-[NSNull length]: unrecognized selector sent to instance 0x107602ce0
Note that nowhere in my file am I calling length on anything. Something behind the scenes is, but I can't figure out what.
Here's my code to set up the UISearchController:
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.definesPresentationContext = true;
self.searchController.hidesNavigationBarDuringPresentation = false;
[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;
self.searchController.searchBar.delegate = self;
self.searchController.delegate = self;
}
By request, here are my delegate methods (implemented just to see if anything gets called after typing the first letter - they don't):
#pragma mark - UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#pragma mark - UISearchControllerDelegate
- (void)didDismissSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)didPresentSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)presentSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)willDismissSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)willPresentSearchController:(UISearchController *)searchController
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"%s", __PRETTY_FUNCTION__);
return true;
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
NSLog(#"%s", __PRETTY_FUNCTION__);
return true;
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
NSLog(#"%s", __PRETTY_FUNCTION__);
return true;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
NSNull is just a singleton object used to represent null. It is traditionally used to wrap around nil values in containers(arrays and dictionaries) that cannot handle nil entries.
This error often comes up when parsing json and trying to add the result in a collection.
Are you doing something like this in your delegate method(s)?
Edit: Judging by the message you are sending to that NSNull (length), you probably get an "empty" result for a string you asked for and expected not be nil.
After burning an entire day struggling with this, it came down to a totally unrelated problem: a corrupted storyboard.
This SO question recommended finding which scene was corrupt and recreating it. Unfortunately there was no way for me to determine that, so after some trial and error, it ended up being the initial view controller in my storyboard, which happened to be a UINavigationController. I deleted that, added it back in, and everything is golden.
I'm writing a stopwatch application for mac, and am currently working on the 'laps' feature. I am putting the laps into a Table View for better organization. I'm using an Array Controller to put things into the table.
Basically, what I'm trying to do is this:
[arrayController addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Lap 1",
#"lapNumber", nil]];
That works fine and dandy, but I'd like to be able to control that number next to lap using an integer representing the number of laps, called numLaps. Thus, my code would be:
[arrayController addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Lap %i",
numLaps, #"lapNumber", nil]];
However, as that is more than two commas before the nil, I think the program is getting screwed up. I am getting the following thrown in the console, though I don't exactly understand what it means / how to fix it:
2013-09-03 16:52:31.515 Popup[3242:303] +[NSMutableDictionary dictionaryWithObjectsAndKeys:]: second object of each pair must be non-nil. Or, did you forget to nil-terminate your parameter list?
2013-09-03 16:52:31.519 Popup[3242:303] (
0 CoreFoundation 0x00007fff9800a0a6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff9920b3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff97fe8e31 +[NSDictionary dictionaryWithObjectsAndKeys:] + 433
3 Popup 0x00000001000035a0 -[PanelController btnLapWasClicked:] + 192
4 AppKit 0x00007fff96082a59 -[NSApplication sendAction:to:from:] + 342
5 AppKit 0x00007fff960828b7 -[NSControl sendAction:to:] + 85
6 AppKit 0x00007fff960827eb -[NSCell _sendActionFrom:] + 138
7 AppKit 0x00007fff96080cd3 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 1855
8 AppKit 0x00007fff96080521 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 504
9 AppKit 0x00007fff9607fc9c -[NSControl mouseDown:] + 820
10 AppKit 0x00007fff9607760e -[NSWindow sendEvent:] + 6853
11 AppKit 0x00007fff96073744 -[NSApplication sendEvent:] + 5761
12 AppKit 0x00007fff95f892fa -[NSApplication run] + 636
13 AppKit 0x00007fff95f2dcb6 NSApplicationMain + 869
14 Popup 0x0000000100001652 main + 34
15 Popup 0x0000000100001624 start + 52
)
Any ideas how to implement what I'm trying to do in another fashion that won't confuse the program?
Thanks.
You should use the modern obj-c notation. That enables you to create dictionaries and arrays in a more natural way.
NSDictionary *dic = #{#"Laps ": #(numLaps), #"someotherkey":#"anditswalue"};
In the code you show the keys and values are not in pairs. You must always insert pairs. (For detailed reference see the NSDictionary documentation.)
NSString *key = #"laps";
NSString *value = [NSStringWithFormat:#"Lap %i", numLaps];
[arrayController addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys:
value, key, nil]];
Also, you need to think over what you want to store in the dictionary. The keys and values are not apparent in your example.
I have a simple document app, based on the document template, which is throwing an exception when the "Revert to Saved -> Last Opened Version" menu item is selected on Mac OS X 10.7.
The exception isn't in my code, it's inside Cocoa. It also doesn't appear to be related to anything I'm doing. My app is very simple (at this stage), almost a vanilla cocoa document based app, based on the template included with the latest stable version of Xcode.
I realise this is probably a bug in Lion, but I need to find a workaround.
See below for the exception, and the entire contents (very small) of my NSDocument subclass.
Steps to reproduce
open any document
type a single character into the text view
select File -> Revert to Saved
click Last Opened Version
Exception
2011-09-04 07:10:29.182 myapp[15433:707] *** -[NSPathStore2 stringByAppendingPathExtension:]: nil argument
2011-09-04 07:10:29.191 myapp[15433:707] (
0 CoreFoundation 0x00007fff89c2b986 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff90c6ed5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff89c2b7ba +[NSException raise:format:arguments:] + 106
3 CoreFoundation 0x00007fff89c2b744 +[NSException raise:format:] + 116
4 Foundation 0x00007fff86d2b172 -[NSPathStore2 stringByAppendingPathExtension:] + 112
5 AppKit 0x00007fff9148f8c3 -[NSDocument _preserveCurrentVersionForReason:error:] + 579
6 AppKit 0x00007fff9147655b __-[NSDocument _revertToVersion:preservingFirst:error:]_block_invoke_3 + 99
7 Foundation 0x00007fff86ef28c3 __-[NSFileCoordinator coordinateReadingItemAtURL:options:error:byAccessor:]_block_invoke_1 + 113
8 Foundation 0x00007fff86ef2f34 -[NSFileCoordinator(NSPrivate) _invokeAccessor:orDont:thenRelinquishAccessClaimForID:] + 202
9 Foundation 0x00007fff86d98a28 -[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:error:byAccessor:] + 663
10 Foundation 0x00007fff86ef284c -[NSFileCoordinator coordinateReadingItemAtURL:options:error:byAccessor:] + 79
11 AppKit 0x00007fff91484b41 __-[NSDocument _revertToVersion:preservingFirst:error:]_block_invoke_1 + 347
12 AppKit 0x00007fff914901e3 -[NSDocument performSynchronousFileAccessUsingBlock:] + 42
13 AppKit 0x00007fff9148fc90 -[NSDocument _revertToVersion:preservingFirst:error:] + 125
14 AppKit 0x00007fff91476cf9 -[NSDocument _revertToDiscardRecentChangesPreservingFirst:error:] + 43
15 AppKit 0x00007fff91477094 __-[NSDocument _revertToDiscardRecentChangesThenContinue:]_block_invoke_3 + 164
16 AppKit 0x00007fff91474851 __-[NSDocument performSynchronousFileAccessUsingBlock:]_block_invoke_1 + 19
17 AppKit 0x00007fff91475bda -[NSDocument continueFileAccessUsingBlock:] + 227
18 AppKit 0x00007fff91490413 -[NSDocument _performFileAccessOnMainThread:usingBlock:] + 466
19 AppKit 0x00007fff9149023f -[NSDocument performSynchronousFileAccessUsingBlock:] + 134
20 AppKit 0x00007fff91495891 __-[NSDocument _revertToDiscardRecentChangesThenContinue:]_block_invoke_2 + 301
21 AppKit 0x00007fff914909a9 -[NSDocument _something:wasPresentedWithResult:soContinue:] + 21
22 AppKit 0x00007fff91381bee -[NSAlert didEndAlert:returnCode:contextInfo:] + 93
23 AppKit 0x00007fff9138e356 -[NSApplication endSheet:returnCode:] + 275
24 AppKit 0x00007fff91381ab4 -[NSAlert buttonPressed:] + 265
25 CoreFoundation 0x00007fff89c1b11d -[NSObject performSelector:withObject:] + 61
26 AppKit 0x00007fff911dd852 -[NSApplication sendAction:to:from:] + 139
27 AppKit 0x00007fff911dd784 -[NSControl sendAction:to:] + 88
28 AppKit 0x00007fff911dd6af -[NSCell _sendActionFrom:] + 137
29 AppKit 0x00007fff911dcb7a -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2014
30 AppKit 0x00007fff9125c57c -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 489
31 AppKit 0x00007fff911db786 -[NSControl mouseDown:] + 786
32 AppKit 0x00007fff911a666e -[NSWindow sendEvent:] + 6280
33 AppKit 0x00007fff9113ef19 -[NSApplication sendEvent:] + 5665
34 AppKit 0x00007fff910d542b -[NSApplication run] + 548
35 AppKit 0x00007fff9135352a NSApplicationMain + 867
36 myapp 0x00000001000018d2 main + 34
37 myapp 0x00000001000018a4 start + 52
)
NSDocument Subclass
#implementation MyTextDocument
#synthesize textStorage;
#synthesize textView;
+ (BOOL)autosavesInPlace
{
return YES;
}
- (id)init
{
self = [super init];
if (self) {
self.textStorage = nil;
self.textView = nil;
textContentToLoad = [#"" retain];
}
return self;
}
- (NSString *)windowNibName
{
return #"MyTextDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
self.textStorage = self.textView.textStorage;
[self loadTextContentIntoStorage];
}
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
return [self.textStorage.string dataUsingEncoding:NSUTF8StringEncoding];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
textContentToLoad = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!textContentToLoad) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:nil];
return NO;
}
[self loadTextContentIntoStorage];
return YES;
}
- (void)loadTextContentIntoStorage
{
if (!self.textStorage || !textContentToLoad)
return;
[self.textStorage beginEditing];
[self.textStorage replaceCharactersInRange:NSMakeRange(0, self.textStorage.length) withString:textContentToLoad];
[textContentToLoad release], textContentToLoad = nil;
}
#end
Is your plist set up correctly when it comes to types?
It appears that NSDocument passes the result of [self fileNameExtensionForType:[self autosavingFileType] saveOperation:NSAutosaveElsewhereOperation] to stringByAppendingPathExtension: (the method that's throwing the exception here). If your app returns nil for this expression, then this exception may result.
You should probably file a bug at Apple for this, but in the meantime, make sure your app returns something non-nil.
Paste this into you document class (e.g. Document.m):
-(NSString*)fileNameExtensionForType:(NSString *)typeName saveOperation: (NSSaveOperationType)saveOperation
{
return #"yourAutosaveExtension";
}
Before, like kperryua said, this method was not implemented and returned nil.