popping to UIViewController causing crash - message sent to deallocated instance - objective-c

I have a UIViewController I am showing as a Modal popover. When that view is done being used I am popping to a particular location in my UINavigationBar:
[[appDelegate.homeViewController navigationController] popToViewController:[[appDelegate.homeViewController navigationController ].viewControllers objectAtIndex:2] animated:YES];
The View Controller presenting the modal UIViewController is mentioned in the crash below:
*** -[ClientDetailsViewController respondsToSelector:]: message sent to deallocated instance 0x8c17650
How can I track this down and see what is causing my crash?

How can I track this down and see what is causing my crash?
Simply activate Zombies.
In Xcode4, hold the alt key while choosing "Product" > "Run" from the menu to show the Schemes dialog (or choose Edit Schemes to show it).
Then in the "Diagnostics" tab, check the "Enable Zombie Objects" checkbox
Now when an object is used after it has been deallocated, you will be able to see which object is concerned and when it has been over-released.
Moreover, don't hesitate to use the static analyzer from the "Product" -> "Analyze" menu so that Xcode will tell you every memory management errors (and others) he can find in your code.
You should always run this "Analyze" tool once in a while and fix ALL the warnings it displays, as it is a very good tool to tell you what may be wrong in your code and is of very good advice.
Not having any warning when you run this tool is not a guarantee that your code won't crash, but having warnings when you run this tool quite guarantee you the're something to be fixed in your code.

Related

Why does my app crash when an NSPanel is closed by pressing Escape?

I have an NSPanel in my app that is crashing the app (EXC_BAD_ACCESS in main()) whenever it is closed by pressing the Escape key. Closing it any other way (File > Close, Cmd-W, clicking the red close button) works fine.
The panel is shown by instantiating its window controller from the storyboard. A reference to the window controller is stored in a dictionary. In the view controller's -viewWillDisappear the window controller is removed from the dictionary.
wc = [[NSStoryboard storyboardWithName:#"Main" bundle:nil] instantiateControllerWithIdentifier:kSBIDPreviewWindowController];
// ...
[windowsOfType addObject:wc];
// ...
[wc showWindow:self];
On close:
-(void)viewDidDisappear {
// ...
if ([windowsOfType containsObject:winController]) {
[windowsOfType removeObject:winController];
}
}
The crash is apparently triggered by removing the window controller from the dictionary. If I keep it, it won't crash.
Some further info:
The panel contains (only) a WebView.
The panel's Release When Closed checkbox is off.
All other options are default (except Hide on Deactivate which is on.)
I can't find the problem with the debugger as the crash happens in main(), ie. after the window has been closed.
Any idea what could be causing this?
And, more generally, which technique should I use to debug such a situation?
Updated 2018-02-19:
Enabling Zombies got me the message -[NSWindowController setNextResponder:]: message sent to deallocated instance 0x60000028a9b0. So something is talking to the window controller after it has been released. Since that isn't my code directly (I'm not even subclassing NSWindowController, and not making any calls to the window controller anywhere), the question remains: What is different when the window is closed by hitting Escape as compared to other methods (like Cmd-W)?
Updated 2018-02-19 #2:
Instruments gave an interesting result. Apparently the WebView which I have on the panel tries to process the pressing of the Escape key after the panel has been closed/deallocated (triggered in my case by the view controller's -viewDidDisappear.)
The Zombie source is -[WebResponderChainSink detach], called (via some intermediate calls) by -[WebHTMLView keyDown:].
It looks like the WebView is not correctly passing on the keypress or something...? Could this mean that a WebView on a panel is a bad idea?
I found the solution to avoid this type of crash; you have to delay the release of the last reference to the window controller until after the current event processing is done (by using dispatch_async(), for example.)
That allows the WebView to do its thing with the keypress.

Why does an object with a retain count of 0 respond to a message?

With ARC turned off:
I create an instance of my custom class using alloc, so it has retain count of 1.
On the next line, I NSLog() the instance (I implemented a description method in my custom class).
On the next line, I release the object.
On the next line, I NSLog() the instance again, i.e. I send it a description message, and I see the same output in the console. I expected some kind of error output.
Here is the relevant code:
AppDelegate.m:
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
Greeter* host = [[Greeter alloc] initWithName:#"Maggie"]; //My custom class
NSLog(#"Greeter %#", host);
[host release];
NSLog(#"Greeter %#", host); //Create error: send a `description` message to an object whose retain count is 0.
return YES;
}
...
...
Greeter.m:
...
- (NSString*)description {
return [
[[NSString alloc] initWithFormat:#"\n\tname: %# \n\tCreated on %#", [self name], [self today]]
autorelease
];
}
--output in Console:--
2015-04-26 21:18:58.914 Flashlight[2380:62826] Greeter
name: Maggie
Created on 2015-04-27 03:18:58 +0000
2015-04-26 21:18:58.915 Flashlight[2380:62826] Greeter
name: Maggie
Created on 2015-04-27 03:18:58 +0000
Similar code in cocoa, causes weird stuff to happen, and Xcode flags the second NSLog() with EXC_BAD_ACCESS.
Response to comments:
I decided to start a new app to try some things, and here is what I discovered:
In Xcode 6.2, even though there is no error in the console, i.e. both NSLog()'s print the same thing, Product>Analyze will point out the line with the error saying: Reference-counted object is used after it is released. And if I click on that message, Xcode shows a nice graphical explanation of how that happened in the code.
If I edit the scheme to enable Zombie objects, then instead of the second NSLog() message, I get an error message:
Flashlight3[606:11093] *** -[Greeter respondsToSelector:]: message
sent to deallocated instance 0x7fb5e1caa8c0
After poking around in Xcode for much too long, I figured out how to edit the scheme. To the right of the Run and Stop buttons, there is a jump bar showing: ProjectName>Platform, which in my case is Flashlight>iPhone6. I clicked on Flashlight, and a drop down list displayed Edit scheme. I clicked on Edit scheme, then under Run/Debug, there is a checkbox for Enable Zombie Objects, which I checked.
Did you compile with debug symbols?
I guess not. I read some Apple docs to figure out how to do that: I clicked on the top line in the Project Navigator, chose Build Settings, then I scrolled down to Build Options, then I selected Build Variants, then I clicked the arrow to reveal Debug and Release. To the right of Debug, I clicked on normal, and I typed in debug.
I'm not sure what that does. I see no difference after doing that.
Do you find your code in the stack trace?
In the Stack Trace area:
Product>Profile
Scroll down the window and choose Zombies.
Then click the red Record button.
A Zombie Messaged popup will appear.
Inside the popup, click the arrow with the gray circle around it.
In the bottom pane, click on the Zombie line.
In the bottom right pane, at the top of pane, select the icon on the far right.
...there are a bunch of names in a list preceded by an icon:
Some of the icons are black. If I click on enough of the black icons, I eventually jump to my code. Doing that is problematic, though, because when I click on one of the black icons, it is hard to get back to the Stack Trace list to try another black icon. Edit: Okay, I found a way to get around that problem: when I click on one of the icons in the Stack Trace pane, it takes me to some code where one of the lines will have a red arrow pointing at it. If I click on the red arrow, it will show me a popup containing the Stack Trace list, and then I can click on one of the other black icons.
Just because an object's retain count goes to 0 and its dealloc method is called, doesn't mean the memory used by the object is instantly turned to garbage. The deallocated object could possibly sit in memory, intact, for a while before the memory space is reused for something else.
That seems to be the case here. The call to log host after it's been deallocated finds that the memory for the deallocated object is still intact so accessing its data works.
But it seems in your test on a Mac results in the memory being handled differently causing the exception.
rmaddy's answer is completely correct. But likely you want to know, how to get an error message in such a case.
There are two options:
Run the static analyzer. It can detect some of these errors.
Enable the zombie option in the scheme. This will keep the instance objects alive and report an error message, if they are used.

Crash upon text selection and deletion from menu in UITextView

My UITextViews crash the app upon text selection and deletion.
Cut, copy, and paste seem to work fine. The only error in the log is:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIMenuController view]: unrecognized selector sent to instance 0xff85ac0'
It is a normal UITextView, and the UIMenuController is untouched and uncustomized. Any ideas?
Happens with iOS 4.3 and 5.0 in simulator and on device.
No more information with zombies enabled, except for a stack trace that I'll need to interpret.. The new Xcode isn't nice about this:
(0x356338bf 0x360ae1e5 0x35636acb 0x35635945 0x35590680 0x37c63925 0x3816b 0x1a557 0x3559222b 0x37a869a7 0x3559222b 0x31671943 0x35607a63 0x356076c9 0x3560629f 0x355894dd 0x355893a5 0x32073fed 0x3794d743 0x29d1 0x2990)
The cause was undocumented (correct me if you find documentation and I'll update this answer) behavior from UITextView and UITextField with their default use of UIMenuController. The "Delete" option is added if your UIText*Delegate implements delete:. When "Delete" is selected from the menu, your field's delegate will then be called with a delete: message. I discovered this by adding an exception breakpoint in the breakpoint listing pane, which gave me the properly symbolicated stack trace that the original exception did not. The crash was caused because I was using delete:(id)sender to service bar button items in a way that required use of the sender. I fixed it by renaming delete: to deletePart:. The user can still delete text by selecting "Cut".
Having view sent to UIMenuController means that you probably assigned the UIMenuController somewhere it shouldn't go. See if you set anything to equal menuController (or whatever your instance variable name is) and see if that causes an issue.
Also, this could be an overrelease happening much earlier in the code where the UIMenuController just happens to allocate in the memory space that was formerly occupied by something that was released too early. Enable NSZombies and see what your error changes to.

NSZombieEnabled isn't helping my obj_msgSend

I'm getting an EXC_BAD_ACCESS with my iPhone app on 0x01ad809b <+0015> mov 0x8(%edx),%edi
I have NSZombieEnabled set to YES but I'm not seeing any class printed out in the debugger like I normally do.
Is there another way to debug this problem?
You have a crash caused, most likely, by corruption of memory, using a variable that isn't initialized, and/or casting a non-object type to an object.
First, post the backtrace of the crash. That will provide more context.
Second, try Build and Analyze. Fix any of the problems that it identifies.
Finally, if this is a new crash, go back to a revision right before the crash and then roll forward until you hit the crash. What are the changes made over that span of time?
With more context -- the crash log, in particular (or backtrace, at the least) -- more specific debugging techniques can be offered.
You can select Breakpoint navigator and add breakpoint on all exceptions. Maybe it will help.
Try with malloc info as well.
Use Instruments to Profile and detect zombies instead.
Change the build target to the Simulator
In the Build menu, select Profile
Instruments will open, then select the Zombies instrument
This automatically sets up the NSZombieEnabled flag and will popup a message whenever a dealloced object is messaged. Clicking the disclosure will show the memory management events of the object.

Using dismissModalViewControllerAnimated won't free any memory

I have a very simple code to show a modal controller (nextController is a class member):
nextController = [[InstructionsScreen alloc] initWithNibName:#"InstructionsScreen" bundle:nil];
[self presentModalViewController:nextController animated:YES];
[nextController release];
And then when the controller should hide:
[self dismissModalViewControllerAnimated:YES];
nextController = nil;
All works good as expected, but when I run instrument Object Allocations it shows that after dismissing the modal controller the memory it allocated is not freed. This becomes a problem because when I show several controllers the memory is over ...
Can anybody give me some clues ? Clang doesn't see any problems, so I'm stuck hitting the memory limit, because the memory of the dismissed controllers won't get released.
EDIT: What I discovered up to now is that it seems to be a leak somewhere in Apple's stuff. Way to reproduce: XCode -> create new project with the template "Utility application". Don't write any code yourself. Just create a new utility application and run it with "Object allocations", choose to see "Created & Still living". Now flip the modal controller few times - you'll see the allocated memory only grows and grows every time the modal controller is appearing and when it's disappearing too ...
There is no leak in the code you show as far as I can see. There could be a leak in InstructionsScreen that would prevent it being deallocated.
I think it's worth running the Static Analyser to see if it finds a leak.
The leak in the Apple template code is interesting. It could be that there is a leak. It seems unlikely but obviously it's not impossible. I would say that it's more likely that it's a false-positive in Instruments, which is why I'd suggest using the Static Analyser.
(You might want to raise a bug report about the leak.)
Modal views are not subviews of the calling view but are instead subview of the apps window and are retained by the window itself. You generally you do not retain a reference to them in the controller that calls them. Instead, evoke the modal view and then have it communicate with the controller by defining the controller as the modal view's delegate.
I think that if you use synthesize to create the accessor for a nextController property defined with retain, then the accessor will retain any object assigned to the property. Simply setting the value to nil will not release the object unless the accessor is set up to do that and I don't think the autogenerated ones do.
You will expressly have to call release before setting to nil.
If this doesn't work, post the code for your definition of the nextController property.