iOS 内存泄漏导致更改视图控制器崩溃

Posted

技术标签:

【中文标题】iOS 内存泄漏导致更改视图控制器崩溃【英文标题】:iOS memory leaks causing crash in changing view controllers 【发布时间】:2012-03-17 13:55:12 【问题描述】:

我创建了两个视图控制器,其中有 UIImage 动画。它经常崩溃并在 xcode 工具中显示内存泄漏。

我的控制器代码-

- (void)viewDidLoad 
     NSArray *firstArray;
     firstArray = [NSArray arrayWithObjects:    
                    [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"up0001" ofType:@"png"]],
                    [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"up0002" ofType:@"png"]],
                                      ::
                                      ::
                   [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"up0035" ofType:@"png"]], nil];


     imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];

     imgView = UIViewContentModeScaleToFill;

     [imgView setAnimationImages:firstArray];

     imgView.animationDuration = 1.75;

     imgView.animationRepeatCount = 0;

     [imgView startAnimating];

     [self.view addSubview: imgView];

- (void)dealloc 
    [super dealloc];
    [imgView release]; 
    imgView = nil;

我正在通过获取 appdelegate 对象并在我的 Appdelegate.m 中调用以下 appdelegate 函数来将视图控制器更改为我的 rootviewcontroller(请提出任何好的方法)

- (void)changeRootViewController:(NSString *)controllerName


    if(self.viewController)
        [self.viewController.view removeFromSuperview];
        self.viewController=nil;
    

    if (controllerName == @"ViewController") 
        ViewController *lviewController =[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        self.viewController =  (RootViewController *)lviewController;
        [lviewController release];
        lviewController.view = nil;
        [self.window setRootViewController:self.viewController]; //LEAKS 100%
     else if (controllerName == @"MainViewController") 
        // Use a different VC as roowViewController
        MainViewController *lviewController =[[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
        self.viewController =  (RootViewController *)lviewController;
        [lviewController release];
        lviewController.view = nil;
        [self.window setRootViewController:self.viewController]; //LEAKS 100%
     else if (controllerName == @"SecondViewController") 
        // Use a different VC as roowViewController
        SecondViewController *lviewController =[[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
        self.viewController =  (RootViewController *)lviewController;
        [lviewController release];
        lviewController.view = nil;
        [self.window setRootViewController:self.viewController];  //LEAKS 100%
    

    [self.window makeKeyAndVisible];

并在我各自的控制器按钮中调用它 -

AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:@"ViewController"];

 AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:@"MainViewController"];

我想从我的主控制器管理视图控制器,在没有导航栏的情况下交换控制器。请帮助我找出最佳方法并避免泄漏。

【问题讨论】:

首先我建议您了解并修复存储泄漏。您是否运行过分析器? 是的,我已经运行了泄漏工具并注释了它向我显示泄漏的代码。像这样 (//Leaks100%) Analyzer 比泄漏工具效果更好,对于第一次通过。它指出你更接近问题。 【参考方案1】:

看这段代码:


if (controllerName == @"ViewController") 
        ViewController *lviewController =[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        self.viewController =  (RootViewController *)lviewController;
        [lviewController release];
        lviewController.view = nil;
        [self.window setRootViewController:self.viewController]; //LEAKS 100%
    

当你分配“lviewController”时,它的保留计数为1; 当您执行“self.viewController”时,我认为 viewController 是一个保留属性,然后 lviewController 保留计数增加到 2; 然后你释放它,平衡之前的alloc,并且retain count返回1; 最后将它分配给rootViewController,这是一个保留属性,所以lviewController的保留计数再次为2; 最后,当您在窗口中“交换”视图控制器时,lviewController 被释放,因此它的保留计数变为 1。如您所见,它永远不会被释放。这意味着每次调用此函数时都会发生泄漏。

【讨论】:

如果您不需要其他地方的“viewController”属性,只需避免它。因此,在您拥有 alloc-init lviewController 之后,将其添加为 self.window 的根控制器,然后(自动)释放它。一旦窗口将处理这个视图控制器(通过分配不同的根控制器),旧的视图控制器将被释放并释放。最后:为什么不使用 ARC? 感谢您的回答。现在肯定会考虑 ARC。【参考方案2】:

您需要更改代码中的一些语句..

这一行没有意义..

   imgView = UIViewContentModeScaleToFill;

使用一个函数,您必须将 UIImageView 属性的值设置为 UIViewContentModeScaleToFillUIImageView 文档中找到。

[imageView setContentMode:UIViewContentModeScaleToFill];

这个也一样……

lviewController.view = nil; //Remove this from your code ..

最后更改 dealloc 函数的实现,并记住 [super dealloc]; 应该在 dealloc 的任何实现中的最后一个。

- (void)dealloc 
    [imgView release]; 
    imgView = nil;
    [super dealloc];

【讨论】:

【参考方案3】:

可能的泄漏是由于“SecondViewController”、“MainViewController”、“ViewController”类中的代码。崩溃的原因是您在 [super dealloc] 之后释放图像视图

试试这个,

- (void)dealloc 

     [imgView release]; 
     imgView = nil;
     [super dealloc];
 

【讨论】:

以上是关于iOS 内存泄漏导致更改视图控制器崩溃的主要内容,如果未能解决你的问题,请参考以下文章

媒体基础多个视频播放导致内存泄漏和未定义时间范围后崩溃

单视图 IOS 7 内存泄漏

iOS Core Data - 意外的内存泄漏

ios在画布上使用display:none绘制图像导致内存泄漏

iOS - 自定义 segue 内存泄漏

无法解释的内存泄漏 swift iOS