Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dismissModalViewControllerAnimated not releasing view controller

Tags:

ios

As part of my app startup, I cycle through several view controllers. Everything works, but the view controllers are not released. ( viewDidUnload and dealloc are never called ). Prior to each state change, I dismiss any presented view controllers. They are dismissed, and viewWillDisappear is called for each view controller:

- (void)stateChange:(NSString *)state {

// Dismiss any exiting modals/popups
[self dismissPopup];
[self dismissModalViewControllerAnimated: NO];        

if([state isEqualToString:@"StateBoot"]) {

    CLRemotePrimaryBootViewController * viewControllerBoot = [[CLRemotePrimaryBootViewController alloc]initWithNibName: @"CLRemoteBootView" bundle:nil];
    [self presentModalViewController:viewControllerBoot animated:NO];   
    [viewControllerBoot release];
}

else if([state isEqualToString:@"StateLogin"]) {

    CLRemotePrimaryAuthViewController *viewControllerAuth = [[CLRemotePrimaryAuthViewController alloc]initWithNibName: @"CLRemoteAuthView" bundle:nil];
    [self presentModalViewController:viewControllerAuth animated:NO]; 
    [viewControllerAuth release];
}

else if([state isEqualToString:@"StateMain"]) {

    [self setSelectedIndex:0];
}

else if([state isEqualToString:@"StateStop"]) {

    // TBD
}

}

After dismissal, self.presentedViewController is in fact nil. Any ideas on how I can coerce iOS to release these unused view controllers?

EDIT -

SOLVED! Hope this post helps others - I was baffled. It turns out that my modal view controllers were derived from a base class that set up observers (NSNotificationCenter) in the init method. These observers must be removed before the observing view controller can be released. In my case this was made more difficult because the observers were blocks instead of selectors. When adding these observers, and id is returned for each one - and so I had to keep track of these in an NSMutableArray and add a method to release the observers in my base class:

+ (void) safeUnsubscribe:(id)object {

if ( object != nil ) {

    if ( [object isKindOfClass:[CLRemotePrimaryBaseViewController class]]) {

        CLRemotePrimaryBaseViewController* viewController = (CLRemotePrimaryBaseViewController*)object;
        [viewController unsubscribe];
    }        
}

} `

`- (void)handle:(NSString *)name usingBlock:(CLObjBlock)block {

id observer = [[NSNotificationCenter defaultCenter] addObserverForName:name object:nil queue:nil usingBlock:^(NSNotification * notification){ block([notification object]); }];
[self.observers addObject:observer];    

}`

// Must call before dealloc or listener will never be released!

`- (void)unsubscribe {

for ( id observer in self.observers ) {

    [[NSNotificationCenter defaultCenter] removeObserver:observer];
}

[self.observers removeAllObjects];

[[NSNotificationCenter defaultCenter] removeObserver:self];

}

like image 247
svenyonson Avatar asked Nov 14 '22 09:11

svenyonson


1 Answers

SOLVED! Hope this post helps others - I was baffled. It turns out that my modal view controllers were derived from a base class that set up observers (NSNotificationCenter) in the init method. These observers must be removed before the observing view controller can be released. In my case this was made more difficult because the observers were blocks instead of selectors. When adding these observers, and id is returned for each one - and so I had to keep track of these in an NSMutableArray and add a method to release the observers in my base class:

+ (void) safeUnsubscribe:(id)object {

if ( object != nil ) {
    if ( [object isKindOfClass:[CLRemotePrimaryBaseViewController class]]) {

        CLRemotePrimaryBaseViewController* viewController = (CLRemotePrimaryBaseViewController*)object;
        [viewController unsubscribe];
    }        
}

} 



- (void)handle:(NSString *)name usingBlock:(CLObjBlock)block {

id observer = [[NSNotificationCenter defaultCenter] addObserverForName:name object:nil queue:nil usingBlock:^(NSNotification * notification){ block([notification object]); }];
[self.observers addObject:observer];    

}


// Must call before dealloc or listener will never be released!

- (void)unsubscribe {

for ( id observer in self.observers ) {

    [[NSNotificationCenter defaultCenter] removeObserver:observer];
}

[self.observers removeAllObjects];

[[NSNotificationCenter defaultCenter] removeObserver:self];

}
like image 116
svenyonson Avatar answered Apr 06 '23 00:04

svenyonson