Search code examples
iosobjective-ccrashautomatic-ref-countingdealloc

ARC releases my object somewhere in Apple's UI library


I have a local variable UINavigationConroller *nav. Not 10 lines after it's declared, within the same method, it is passed to [self presentViewController:nav animated:YES completion:nil] (self is a UIViewController). I know passing nil here is OK because the documentation says it is.

Just before passing it in, everything's fine. However, while it's in there ARC deallocates it and the app soon crashes when something in Apple's UI library calls [UINavigationController isKindOfClass:], presumably on my nav object. Here's the console output:

2015-03-20 13:33:50.729 Now[9183:3980870] Presenting view controllers on detached view controllers is discouraged <MyViewController: 0x125042200>.
2015-03-20 13:33:50.730 Now[9183:3980870] *** -[UINavigationController isKindOfClass:]: message sent to deallocated instance 0x12601c6e0

I've been stepping in, out, and through this class and assembly code for a couple days, Googling as much as I can, and can't seem to fix it. My only solution left was to call [nav retain] just before presentViewController, and [nav release] immediately after, but ARC forbids this. This is a huge, old project so we can't just turn off ARC.

How do I keep nav form being deallocated before it's done being used?

Update:


I've inspected this using the Zombie profiler. I've discovered that it is indeed a UINavigationController, and is indeed being deallocated within UIKit:

A screenshot of the Zombie profiler

The most telling thing is the top two lines, which show it going from 960B on allocation, immediately to 0:

A screenshot of the top 2 frames in the Zombie proviler, hilighting the immediate nullification

I'm this looks atypical, and throws up red flags for me.


Solution

  • This has been solved. It turns out that back when this codebase was first written, it used a "stashing" system, that would hold any modal UIViewController in a field and then dismiss it. When needed again, it would present that stashed modal and nilify the stash variable.

    The problem comes in how I was handling things, not knowing about this system. In directly presenting or dismissing the modal, I was inadvertently setting up a situation in which this system presented a zombie UINavigationController. After using this system, it works as intended.