Amos
Amos

Reputation: 888

How do I make sure popToRootViewControllerAnimated works?

I have a UINavigationController that gets three views pushed onto it as the user cycles through pages (always same order) - I'll call them views0, 1, and 2 to line up with navigation controller indicies. The views are created in Storyboard.

When the progression of views is done, and the user wants to return to the beginning, I use popToRootViewControllerAnimated:YES in response to a button push, and the UI appropriately returns to the view0. However, I occasionally get "phantom" log statements in response to app-wide notifications if I go through the cycle again, making it clear that view1 (the middle view) never got fully dealloc'ed. I'm using ARC in xcode 4.2.1 with iOS5+ code only, so ARC should be taking care of things pretty well.

I've seen a few posts suggesting that ARC won't dealloc views whose reference count hasn't dropped to 0, so I've done everything I can to set properties to nil when done, and a double-check shows that nothing is left over when I push to the final view...and nothing outside of the NavigationController references view1 (that I know of). Profiling the app for zombies and memory leaks don't yield anything.

How can I view/log/debug what might still be referencing the view? How can I tell it's been successfully dealloc'ed without putting things in it that would prevent the dealloc?

My code is (essentially) as follows:

view0 pushes to view1 using a "Push" segue in storyboard.

View 1:

- (void)viewDidLoad
    { 
    [super viewDidLoad];

    /* register as observer for some notifications */
    /* set properties and format an image or two */
    }

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

/* start some animation here */
}


- (void) receiveNotification {

NSObject *newObject = [[NSObject alloc] init];

[newObject doStuff];

/* Remove notification observers */

}


- (void)objectDelegateMethod:(NSDictionary *) dataReturned {

/* do stuff with dataReturned */
self.propertyName = dataReturned;

[self performSegueWithIdentifier:@"AllDone" sender:self];

}


- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

if ([[segue identifier] isEqualToString:@"AllDone"])
{

View2ViewController *destinationView = [segue destinationViewController];

destinationView.propertyMagic = self.propertyName;

[self setPropertyName:nil];
//do same with all other properties

}

View2:

- (void)viewDidLoad
{

/* display things based on self.propertyMagic */

}


- (IBAction)userStartsOverButton:(id)sender {

[self.navigationController popToRootViewControllerAnimated:YES];

}

Given the above (rough) structure, if I don't remove view1 as an observer of notifications, it continues to respond and output to the log even though I can't see why it hasn't been dealloc'ed. Even when I DO remove the observers, memory usage continues to increase as I cycle through app runs and eventually things crash (with no leakages detected in instruments).

How do I figure this out?

Upvotes: 0

Views: 1462

Answers (2)

Vincent Gable
Vincent Gable

Reputation: 3463

If you've run leaks and zombies, then … you probably don't have any leaks or over-releases.

To "see" a dealloc happen under ARC, you can add an empty logging dealloc to your class:

- (void)dealloc
{
    NSLog(@"%s:%d", __func__, __LINE__);
}

Upvotes: 1

Max
Max

Reputation: 989

One thing you could check is if any other Object has a (strong) pointer to view1. If so, you might want to change it to (weak) or just not keeping a reference to it. (Look for a possible retain cycle between view0 and view1 AND between view1 and view2, maybe they are keeping references to each other).

ARC will release on object if it is not owned by any other object anymore. So you could also try overwriting to -popToRootViewControllerAnimated: method on view0 and call something like:

self.view1 = nil;

If view0 is the only object keeping a reference to view1, view1 should be released (dealloced).

Upvotes: 0

Related Questions