My View Controller gets deallocated when the app g

2019-09-03 10:00发布

问题:

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];

回答1:

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 replacing self.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, implement dealloc (or add to it if you have implemented already):

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


回答2:

The issue:

  1. MyViewController was re-instantiated every time MyViewController *myViewController = [storyBoard instantiateViewControllerWithIdentifier:@"MyViewController"]; was called.

  2. Using ARC, it looks like when the app goes to the foreground, some cleaning is done.

  3. 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.