Core Data: crash when last window is closed - objective-c

I get invariably this error when I close the last window of my app:
Application Specific Information: objc_msgSend() selector name:
respondsToSelector: objc[42729]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0
libobjc.A.dylib 0x00007fff8cc9a150 objc_msgSend_vtable5
+ 16 1 com.apple.AppKit 0x00007fff8fbca814 -[NSApplication supplementalTargetForAction:sender:] + 63 2 com.apple.AppKit 0x00007fff8fab91e4
_objectFromResponderChainWhichRespondsToAction + 155 3 com.apple.AppKit 0x00007fff8fab8feb
_NSTargetForSendAction + 3255 4 com.apple.AppKit 0x00007fff8fab832f -[NSApplication targetForAction:to:from:] + 682 5
com.apple.AppKit 0x00007fff8fab7e00 -[NSMenu
_enableItem:] + 403
I confess that the document nib has two windows. I want the "auxiliary window" to be closed and deallocated when the main window is closed. How should I do? Maybe these errors com from here… I'm using Core Data and ARC.
Regards

I found something which seems to solve the problem. But I don't understand what's happening and I really dislike this.
In IB, the file's owner has a "window" outlet who points to the document window; but there is no #property NSWindow window; in the default code of the NS(Persistent)Document.
I had to make a panel a "child window" of the doc's main window, so I add a #property NSWindow mainWindow. The new "mainWindow" outlet points to the same window as the "window" outlet.
And suddenly no more crash, no more zombie. What happened? I'm baffled.
After reflexion: I have added a pointer to the document window, so the ARC counter never reaches zero. I suppose I had a missing reference somewhere to the _window of the NSDocument, which is now balanced by my outlet.

Related

EXC_BAD_ACCESS when closing NSDocument window (ARC enabled)

I'm working on converting a document-based application from Garbage Collection (it ran fine under 10.6) to Automatic Reference Counting (trying to get it to compile and run for 10.12). I'm getting a consistent EXC_BAD_ACCESS when the last window is closed. Nothing is flagged by the static analyser.
I used Instruments to look for Zombies, and indeed there appears to be a release message sent to a deallocated object. Here is the trace:
# Event ∆ RefCt Timestamp Responsible Library/Responsible Caller
173 Release -1 3 00:05.226.677 Foundation __48-[NSFileAccessArbiterProxy removeFilePresenter:]_block_invoke
174 Release -1 2 00:05.226.679 Foundation -[NSFilePresenterXPCMessenger invalidate]
175 Retain +1 3 00:05.226.823 Foundation -[NSBlockOperation initWithBlock:]
176 Retain +1 4 00:05.226.858 AppKit -[NSDocument close]
177 Release -1 3 00:05.227.350 Foundation -[NSFilePresenterXPCMessenger dealloc]
Retain/Release (2) 00:05.227.484 AppKit -[NSDocumentController removeDocument:]
180 Release -1 2 00:05.227.485 AppKit -[NSDocumentController removeDocument:]
Retain/Release (2) 00:05.227.496 AppKit -[NSUIActivityManager addProvider:toUserActivity:withSetter:]
183 Autorelease 00:05.227.499 AppKit -[NSWindowController _windowDidClose]
184 Release -1 1 00:05.228.172 Foundation -[NSAutoreleasePool drain]
185 Release -1 0 00:05.228.184 Foundation -[NSBlockOperation dealloc]
186 Zombie -1 00:05.242.579 AppKit -[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]
The difficult I am having in diagnosing this problem is that I can see the message being sent to the Zombie, but because I do not release any objects (it is all done by ARC), I'm guessing there is an implicit release going on somewhere. But I'm not sure where to look.
When in the debugger, lldb complains of a crash in main.m at:
return NSApplicationMain(argc, (const char **) argv);
Any help would be greatly appreciated. Thank you.
After doing more research, the problem is still unsolved, but I have a clue:
Thank you for your response. Yes, I am at this point assuming it is a memory management issue. Is there way to track down the culprit? It doesn't seem like using Zombies in Instruments is helping: it points to a problem, but does not help me target the problem. That is, the offending line according to Instruments appears to be "-[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]"; but I never issued that line. I have made what might be a little progress towards figuring things out.
The structure I am using in the document is:
NSDocumentController: default, not subclassed
NSDocument: subclassed, MyDocument; also the delegate of window
NSWindowController: default, not subclassed
NSWindow: MyDocument.xib, MainMenu.xib
I tried setting the delegate of the open window to nil as follows:
-(void)windowWillClose:(NSNotification *)notification
{
windowOpen = YES;
NSArray *windowControllers = [self windowControllers];
NSWindowController *currentWindowController = [windowControllers firstObject];
NSWindow *windowForCurrentController = [currentWindowController window];
NSDocument *w = [windowForCurrentController delegate];
[windowForCurrentController setDelegate:nil];
}
This causes the same crash.
Then, I thought perhaps the currentWindowController (or the application) was messaging a deallocated window. So I tried adding the line (at the end of the method above):
[currentWindowController setWindow:nil];
This gets rid of the crashes, but introduces new problems (such as when trying to load new files, etc.). But I'm wondering if this is a clue to help solve the overall problem.
The problem was that the app delegate was set to being MyDocument (the NSDocument subclass). The problem was solved by creating a standard AppDelegate class (NSObject, implementing the NSApplicationDelegate protocol), creating a corresponding NSObject in the XIB and setting it to type AppDelegate, and then making AppDelegate the delegate for MyDocument.
I seems that the source of the problem was that the MyDocument object was being deallocated, but it was still the delegate of the NSWindow subclass. The NSWindow then sent a dealloc message to the delegate, but it was already deallocated, causing a crash.
Here is the chain that solved it (long but instructive).

Cocoa: Crash in _NSDisplayOperationStack; Need Guidance

The Problem
I'm receiving crash reports from users that look like this:
Code Type: X86-64 (Native)
Parent Process: launchd [223]
Date/Time: 2012-03-22 11:28:33.087 +0800
OS Version: Mac OS X 10.7.3 (11D50)
Report Version: 9
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: 0x000000000000000d, 0x0000000000000000
VM Regions Near 0:
-->
__TEXT 000000010c202000-000000010c29c000 [ 616K] r-x/rwx SM=COW /Applications/CodeKit.app/Contents/MacOS/CodeKit
Application Specific Information:
objc_msgSend() selector name: release
objc[22113]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff904f5390 objc_msgSend_vtable14 + 16
1 com.apple.Foundation 0x00007fff8f664137 empty + 61
2 com.apple.Foundation 0x00007fff8f666c10 dealloc + 24
3 com.apple.Foundation 0x00007fff8f666bd1 -[NSConcreteMapTable dealloc] + 64
4 com.apple.AppKit 0x00007fff892bc52c -[_NSDisplayOperation dealloc] + 84
5 com.apple.CoreFoundation 0x00007fff8fdc7ca0 CFRelease + 176
6 com.apple.CoreFoundation 0x00007fff8fdf0742 -[__NSArrayM removeObjectAtIndex:] + 434
7 com.apple.AppKit 0x00007fff892bc408 -[_NSDisplayOperationStack exitDisplayOperationForWindow:] + 417
8 com.apple.AppKit 0x00007fff892be2fc -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 7136
9 com.apple.AppKit 0x00007fff892b6429 -[NSView displayIfNeeded] + 1676
10 [SEE DISCUSSION BELOW]
Discussion
Lines 10 and below vary wildly between reports (and hence are unrelated to the crash). However, the sequence from lines 1 to 9 is always the same. Every crash contains this exact sequence. I've googled "_NSDisplayOperationStack" and I've found similar crash reports for dozens of apps (including well-known ones such as Omni apps and Apple's Motion.)
What I Need
Because the crash is coming from Core Foundation, I have no idea where to begin looking for the problem. It seems to be deep inside Cocoa's private view-drawing machinery. Worse still, I can't replicate the crash on my machine at all, so I can't trace it with Instruments. But I've received many reports with the pattern above, so I know it's a problem. Worse STILL, the users can't even reproduce the crash reliably -- it's completely intermittent.
I'm hoping the above sequence looks familiar to someone and they can give me guidance on where to start looking for the problem. Thank you.
I posted this same question over at the Apple Developer forums and one engineer told me that it looked like the stack trace had to do with concurrent view drawing, which is a feature that was introduced in 10.6.
I went through all of my NIB files and found two NSButton instances that were set to draw concurrently --- this was not intentional; I must have checked that box by accident at some point.
I disabled the concurrent drawing for both of them and this crash has magically disappeared.
In some cases disabling concurrent drawing for just some buttons doesn't help. I got the same error as the author's ("_NSDisplayOperationStack underflow raised during heart beat."). Lucky there is a master switch in a window that disables all concurrent drawing for one window:
[self.window setAllowsConcurrentViewDrawing:NO];
Also opening the the window via a block executed on the main queue helped:
dispatch_async(dispatch_get_main_queue(), ^{
if(nil == self.someWindowController) {
self.someWindowController = [[[SomeWindowController alloc] initWithWindowNibName:#"SomeWindowController"] autorelease];
}
[self.someWindowController.window makeKeyAndOrderFront:self];
});
Showing the window from within a block just postpones the execution a little bit but for my application, some additional window opening via menu shortcut, a combination of the two were the only thing working.

UIKit: [UIViewController mutableChildViewControllers] crash?

I recently received a crash report from itunes connect. Actually it's the only crash report I got from thousands of users, yet. It's an iPod4,1 device. Interesting parts are:
Date/Time: 2012-02-27 22:53:27.596 +0800
OS Version: iPhone OS 5.0.1 (9A405)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x00000000, 0x00000000
Crashed Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
It seems that the crash occurs when a row from a table view is selected, and a new view controller is pushed into navigation. According to my code, the new view controller is created already, so the crash occurred in UINavigationController.
It doesn't look like the fault of the code I wrote. And I wonder if I'm correct on this? How do I debug this problem?
It sounds like the user got a low-memory warning. UINavigationControllers will retain their views, whereas tabbed ones will pop off the invisible ones. However, the low memory code is still getting called. Check your warning handlers prior to reaching that spot. Also, test by hitting "Simulate Memory Warning" under the hardware menu at all entry and exit points.
http://forums.macrumors.com/showthread.php?t=876419 shows a mess of what happens when you don't.
iphonedevsdk.com/forum/iphone-sdk-development/14225-uinavigationcontrollers-and-didreceivememorywarning.html has a nice comment or so on how to handle this.
I'm betting your view controller loads something and caused the memory warning. Ensure the user can't just stack tons of items on top of each other, and make sure your app is profiled to remove as many leaks as necessary to keep the app up.
The above may not be on the mark, but should be related.
Final note, don't use ARC. Something that disallows calling superclass functions is bound to screw up. If you understand bridging Core Foundation, then perhaps ARC is fine. I personally avoid it at all costs b/c memory becomes randomly handled by Apple's under-the-hood. I've seen their stuff fail way too much
I got it! I had the same problem too and in your code it looks like that a button is pressed, which causes the crash!
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
Here is my suggestion:
Two things to solve a SIGABRT:
1) SIGABRT happens due to a runtime exception that isn't caught. When this happens there is some info written to the debugger console or the device console that explains the exact reason for the exception. You haven't shown us this text. It starts "Terminating application due to ..."
Show us that text.
2) If you run your app in the debugger and set a breakpoint on the exception throw function the app will stop when the exception is thrown and this will usually be enough to figure it out. Go to the debugger breakpoint pane and at the bottom left is a control that when clicked allows you to set an exception breakpoint.

NSDrawer delegate pointing to deallocated object?

A user has sent in a crash report with the stack trace listed below (I have not been able to reproduce the crash myself, but every other crash this user has reported has been a valid bug, even when I couldn't reproduce the effect). The application is a reference-counted Objective-C/Cocoa app.
If I am interpreting it correctly, the crash is caused by attempting to send a drawerDidOpen: message to a deallocated object. The only object that should be receiving drawerDidOpen: is the drawer's delegate object (nowhere does any object register to receive drawer notifications), and the drawer's delegate object is instantiated via the XIB/NIB file, wired to the delegate outlet of the drawer, and not referenced anywhere else.
Given that, how can I protect against the delegate getting dealloc'd before the drawer notification? Or, alternately, what have I misinterpreted that might be causing the crash?
Crash log/stack trace:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: drawerDidOpen:
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff8272011c objc_msgSend + 40
1 com.apple.Foundation 0x00007fff87d0786e _nsnote_callback + 167
2 com.apple.CoreFoundation 0x00007fff831bcaea __CFXNotificationPost + 954
3 com.apple.CoreFoundation 0x00007fff831a9098 _CFXNotificationPostNotification + 200
4 com.apple.Foundation 0x00007fff87cfe7d8 -[NSNotificationCenter postNotificationName:object:userInfo:] + 101
5 com.apple.AppKit 0x00007fff8512e944 _NSDrawerObserverCallBack + 840
6 com.apple.CoreFoundation 0x00007fff831d40d7 __CFRunLoopDoObservers + 519
7 com.apple.CoreFoundation 0x00007fff831af8c4 CFRunLoopRunSpecific + 548
8 com.apple.HIToolbox 0x00007fff839b8ada RunCurrentEventLoopInMode + 333
9 com.apple.HIToolbox 0x00007fff839b883d ReceiveNextEventCommon + 148
10 com.apple.HIToolbox 0x00007fff839b8798 BlockUntilNextEventMatchingListInMode + 59
11 com.apple.AppKit 0x00007fff84de8a2a _DPSNextEvent + 708
12 com.apple.AppKit 0x00007fff84de8379 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 155
13 com.apple.AppKit 0x00007fff84dae05b -[NSApplication run] + 395
14 com.apple.AppKit 0x00007fff84da6d7c NSApplicationMain + 364
15 (my app's identifier) 0x0000000100001188 start + 52
edit: To clarify: This crash happened once in thousands or maybe tens of thousands of virtually-identical usage scenarios. I don't retain/release/alloc/dealloc/anything-memory-management the delegate object anywhere in my code; I don't register any object for any drawer notifications of any kind in my code; my code has no variables (nor ivars) pointing to the delegate object.
What it looks like to me is that when the NIB was unloaded (as in whatever the Cocoa system does when the document window gets closed), somehow the drawer's delegate object was dealloc'd before the drawer object itself, but the Cocoa system is supposed to prevent that from happening (and seems to handle it correctly in the vast majority of cases).
The delegate has been released to the point of deallocation without first being unregistered from the notification center (in this case, the delegation is through the notification center, not directly).
An easy fix is to call NSNotificationCenter's -removeObserver: method from your delegate's -dealloc method.
Check the backtrace -- it is through the notification center that the crash happens. Most likely, when the class is connected via setDelegate: (via the NIB file), it is done so as a notification observer.
Regardless, the relationship between notification center and your object is the same as between the object in IB and your object; weak. That is, there is no retain and, thus, your delegate is being freed too early (or, alternatively, you are over-releasing the object somewhere).
In any case, you need to make sure your delegate is retained by something somewhere for the duration of its usefulness.

NSCollectionView in 10.6/Xcode 3.2

in Xcode 3.1.2 I used to load the nib of the NSCollectionViewItem in my subclass of NSCollectionViewItem like this:
-(id)copyWithZone:(NSZone *)zone
{
id result = [super copyWithZone:zone];
[NSBundle loadNibNamed:#"PersonView" owner:result];
return result;
}
In Xcode 3.2 under 10.6 the same method doesn't yield to an error, but it doesn't load the view in the NSCollectionView either.
Is there something else that needs to be done to make the view show up?
Or is there even a better way of doing this that comes with the change of NSCollectionItem's superclass to NSViewController?
After all, overriding copyWithZone to achieve this standard functionality always seemed like a hack to me. I think one should be able to specify the nib that's supposed to be used in IB, but it seems like Apple doesn't think so.
I did have a look at the example that is available in the documentation, but there the NSCollectionViewItem is instantiated programmatically using initWithNibName, but I would like to create it in the IB.
UPDATE:
I did what kperryua suggested, but now I can't access outlets from the NSCollectionViewItem. Here's what I'm trying to do:
- (void)setRepresentedObject:(id)object {
if (object) {
[labelName setValue:[object name]];
}
}
I binded the label name to the file owner which is my NSCollectionViewItem. That used to work perfectly in 10.5, but now the outlet is not assigned(I checked that with GDB).
image showing the bindings http://img21.imageshack.us/img21/671/picya.png
UPDATE 2:
I also binded the NSCollectionView's itemPrototype to my subclass of NSCollectionViewItem(PersonController).
image showing bindings http://img503.imageshack.us/img503/4672/pic2d.png
Now both the File's Owner of the PersonView.nib and the itemPrototype of the NSCollectionView point to my subclass.
image showing console output http://img340.imageshack.us/img340/6184/pic3.png
As you can see in the screenshot the item are displayed, but the text of the label can't be changed as the outlet labelName isn't accessible.
I also logged the name that I'm trying to set to make sure it isn't 'Name'.
What needs to be done to change the label's value?
Any help would be appreciated.
Yes, Snow Leopard makes this much easier. In IB, click on the NSCollectionViewItem and set the nib name and bundle name (just leave it blank for the main bundle). In your PersonView nib, make the NSCollectionViewItem the File's Owner and connect the -view outlet to a view in that nib. (It looks like you might have this set up like that already in that nib.) Everything else should be automatic, and overriding copyWithZone: shouldn't be necessary.
To sync the property of the representedObject with the Value of an IB Element, you might want to use the Cocoa-bindings. Bind the Value of the TextField to the Model Key Path representedObject.name of the File's Owner in this case.
I had that working with 10.6 Xcode 3.2 but what can't get to work is what you did: Connecting an IB Element to an Outlet of my CollectionViewItem. I have a custom subclass of CollectionViewItem and everything set up as you have. But when running the application it fails stating
[NSTextField copyWithZone:]: unrecognized selector sent to instance 0x210a60
2009-10-19 13:05:18.772 WrapperTest[24122:a0f] An uncaught exception was raised
2009-10-19 13:05:18.774 WrapperTest[24122:a0f] -[NSTextField copyWithZone:]: unrecognized selector sent to instance 0x210a60
2009-10-19 13:05:18.779 WrapperTest[24122:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTextField copyWithZone:]: unrecognized selector sent to instance 0x210a60'
*** Call stack at first throw:
(
0 CoreFoundation 0x977f658a __raiseError + 410
1 libobjc.A.dylib 0x9767ff49 objc_exception_throw + 56
2 CoreFoundation 0x978429db -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x9779e026 ___forwarding___ + 950
4 CoreFoundation 0x9779dbf2 _CF_forwarding_prep_0 + 50
5 CoreFoundation 0x97789a5a -[NSObject(NSObject) copy] + 42
6 AppKit 0x918ce1d7 -[NSViewController setTitle:] + 70
7 AppKit 0x91167dab -[NSNibOutletConnector establishConnection] + 406 ...
I'm not sure why those NSTextFields are missing their copyWithZone since they should implement it
I fixed that, I wasn't aware, that I needed to declare those Outlets as properties of the view, everything including bindings seem to work.