My View Controller class gets deallocated when the app goes to the background. I'm using ARC.
I have a UIViewController that subscribes to a notifications when the app becomes active and executes a method. But once the app is about 30 secs in the background and then resumes, the app crashes with "message sent to deallocated instance".
Enabling Zombie objects shows that the View Controller itself is the Zombie.
Thank you!
Instantiation of my view controller (in AppDelegate):
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MyViewController *myViewController = [storyBoard instantiateViewControllerWithIdentifier:@"MyViewController"];
The foreground notification in AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationForegrounded object:self];
}
The foreground notification in the view controller:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeForeground) name:kNotificationForegrounded object:nil];
}
I tried creating a strong reference in the AppDelegate, but the view controller still gets deallocated:
@property (strong, nonatomic) MyViewController *myViewController;
I tried adding the view controller to an array and have a strong reference to the array in the AppDelegae, but still I get the same results:
@property (strong, nonatomic) NSMutableArray *viewControllers;
//...
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MyViewController *myViewController = [storyBoard instantiateViewControllerWithIdentifier:@"MyViewController"];
self.viewControllers = [[NSMutableArray alloc] init];
[self.viewControllers addObject:myViewController];
There are two issues here - your app delegate is not managing its ownership of objects correctly, and the view controller is not cleaning up after itself.
Every time you execute the code to instantiate an
MyViewController
, you release ownership of all existing view controllers by replacingself.viewControllers
with a new instance. Only allocate that once, and add and remove objects as needed. Also, you never use your strong property, only a local instance variable of the same name. You should probably actually make sure that you want this code to run over and over (I assume that it is, given the symptoms and information you describe).Also, in
MyViewController
, implementdealloc
(or add to it if you have implemented already):The issue:
MyViewController
was re-instantiated every timeMyViewController *myViewController = [storyBoard instantiateViewControllerWithIdentifier:@"MyViewController"];
was called.Using ARC, it looks like when the app goes to the foreground, some cleaning is done.
When the app was moved to the foreground,
@dealloc
and the foreground notification were called simultaneously from two different threads, so when the selector method was executed on the notification, the (no references) view controller was already marked as or to-be deallocated.The solution:
As @Carl suggested I added
[[NSNotificationCenter defaultCenter] removeObserver:self];
except not in@dealloc
, but at an earlier point when the view controller usage was done. I assume doing it right before re-instantiating would work as well.