UIViewController not being released from memory wh

2019-08-30 22:49发布

问题:

I have a UINavigationController and I'm trying to release from memory every UIViewController once another one is on top of the stack. I assign the viewControllers property of the UINavigationController to the new UIViewController and then pop into it. This way I always have just one UIViewController in stack. However, the memory keeps adding up every time I create a new UIViewController. Dealloc is called, but the memory usage remains the same.

You can download the example project HERE

FirstViewController.h

#import "SecondViewController.h"

@interface FirstViewController : UIViewController

-(IBAction)goToSecond:(id)sender;

@end

FirstViewController.m

#import "FirstViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"%@", self.navigationController.viewControllers);

}

-(void)goToSecond:(id)sender{

    SecondViewController *secondVC = [[SecondViewController alloc]init];
    [self.navigationController setViewControllers:@[secondVC]];
    [self.navigationController popViewControllerAnimated:NO];
}

-(void)dealloc{

    NSLog(@"FirstVC dealloc");
}
@end

SecondViewController.h

#import "FirstViewController.h"

@interface SecondViewController : UIViewController

-(IBAction)goToFirst:(id)sender;

@end

SecondViewController.m

#import "SecondViewController.h"

@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"%@", self.navigationController.viewControllers);

}

-(void)goToFirst:(id)sender{

    FirstViewController *firstVC = [[FirstViewController alloc]init];
    [self.navigationController setViewControllers:@[firstVC]];
    [self.navigationController popViewControllerAnimated:NO];

}

-(void)dealloc{

    NSLog(@"SecondVC dealloc");
}

@end

回答1:

Navigation controller should not be used as you intended. You should call pushViewController and popViewController for present/dismiss your viewControllers. If you have memory issues, try to release memory in didReceiveMemoryWarning callback



回答2:

I'm not sure about the benefit of a uinavigationcontroller but anyway you could add this snippet on your .m of your uiviewcontrollers

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];    
    if (self.navigationController.viewControllers.count > 1) {
        NSMutableArray *newViewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
        [newViewControllers removeObject:[controllers objectAtIndex:1]];
        self.navigationController.viewControllers = newViewControllers;
    }
}

And instead of

[self.navigationController setViewControllers:@[firstVC]];
[self.navigationController popViewControllerAnimated:NO];

you can set

[self.navigationController pushViewController:[[FirstViewController alloc] init] animated:NO];


回答3:

You are using pop to go further, but you need to use push if you want to go to the next ViewController.

-(void)goToSecond:(id)sender{
    SecondViewController *secondVC = [[SecondViewController alloc]init];
    [ self.navigationController pushViewController:secondVC animated:YES];
}

And in the SecondViewController to go back to your FirstViewController you should use pop

-(void)backToController
{
    [self.navigationController popViewControllerAnimated:YES];
}

In your case

-(void)goToFirst:(id)sender
 {
        [self.navigationController popViewControllerAnimated:YES];
 }


回答4:

I uploaded a simple app to GitHub, with the fake navigation bar that i was talking about in my comment, hope it helps for your needs: https://github.com/yosihashamen/HelpersApps

Be ware that you must keep on "BaseViewController" alive at all times.



回答5:

What I mean is something like this.

In your FirstViewController use presentViewController instead of push adding a new UINavigationController to the SecondViewController

-(void)goToSecond:(id)sender{
    SecondViewController *secondVC = [[SecondViewController alloc]init]; 
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:secondVC];
    [self presentViewController:nav animated:YES completion:NIL];

}

In the SecondViewController add an UIBarButtonItem to the Navigation bar

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleDone target:nil action:@selector(goToFirst:)];
self.navigationItem.backBarButtonItem = backButton;

And implement dismiss method.

-(void)goToFirst:(id)sender
 {
    [self dismissViewControllerAnimated:YES completion:NULL];
 }


回答6:

Try out setViewControllers:animated:

This allows you to explicitly set the view controllers on the UINavigationController stack, like you are doing, and it will automatically handle the navigation animation without you having to call popViewControllerAnimated:

This is useful if you have a multi-view journey where you need to get rid of the screens that have been shown so far but maintain the navigation animation (eg. app demo on launch) or if you want to easily push multiple view controllers on the navigation stack at once.

Apple doc here: https://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html#jumpTo_21