user1191140
user1191140

Reputation: 1579

Memory not releasing after popToRootViewControllerAnimated

I am using navigationController in my app. After I push and pop a view controller 3 times my app crashes because of low memory. This is my code below.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        HomePageVC *homePage = [[ViewController alloc] homePage = [[ViewController alloc] initWithNibName:@"MainView-iPad" bundle:nil];
        navigationController = [[UINavigationController alloc] initWithRootViewController:homePage];
        self.window.rootViewController = navigationController;
        [self.window makeKeyAndVisible];
        return YES;
}

When a user pushes a button, I send him to another view Controller.

 -(IBAction)showMap:(id)sender
 {
    MapViewController *mapViewController = Nil;
    mapViewController = [[MapViewController alloc] initWithNibName:@"MapView-iPad" bundle:nil];
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate.navigationController pushViewController:mapViewController animated:YES];
 }

When he want to come back to rootView Controller, I do

-(IBAction)goBack:(id)sender
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate.navigationController popToRootViewControllerAnimated:YES];
}

Now after doing this few times, gradually the didReceiveLowMemory gets called and the app crashes.

To debug some more, I printed the memory usage in loop.

-(void) report_memory {
    struct task_basic_info info;
    mach_msg_type_number_t sizeM = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(),
                               TASK_BASIC_INFO,
                               (task_info_t)&info,
                               &sizeM);
    if( kerr == KERN_SUCCESS ) {
        NSLog(@"Memory usage: %.4lf MB", info.resident_size/1000000.0);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
}

The outputs are

When the app Launches    : Memory usage: 137.8263 MB
After showMap First Time : Memory usage: 206.2172 MB
Gone Back Home           : Memory usage: 223.6580 MB   ==> MapVC didn't release

After showMap Second Time: Memory usage: 227.2172 MB
Press Go Back Home       : Memory usage: 250.2172 MB   ==> MapVC didn't release

After showMap Third Time : App Crashes

My lowMemory is written as

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    NSLog(@"Got Low Memory From %@",[self class]);
}

To add more surprise I got Low Memory Warning from both HomePageVC and MapVC. If I have alreay pooped out MapVC how did I receive lowMemory from it ? And why memory consumed by MapVC did not get released ? I am using ARC.

Upvotes: 0

Views: 1633

Answers (2)

pheedsta
pheedsta

Reputation: 2080

I was having the same problem in my code (using ARC) where my UIViewController was not being released after a call to popToRootViewControllerAnimated:

The reason for my error was due to an NSTimer in the UIViewController. I was trying to invalidate the timer in dealloc but because my NSTimer was using target:self (i.e. retaining a pointer to my UIViewController) dealloc was never being called.

To fix this issue, I invalidated the timer in viewWillDisappear.

Upvotes: 4

user1191140
user1191140

Reputation: 1579

So looks like iOS is not releasing memory unless it is needed. I added some more code to alloc lots of memory. While view controllers were popped, memory was never released. But when didReceiveMemorywarning was called, actually I got the memory back. One more thing I learnt by this exercise is to release the view when it is not the active window from apple tutorial here.

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    if ([self.view window] == nil)
        self.view = nil;
}

Upvotes: 1

Related Questions