【问题标题】:UIViewController memory leak issuesUIViewController 内存泄漏问题
【发布时间】:2010-10-11 03:40:41
【问题描述】:

与有关创建和销毁 UIImagePickerController 实例的已知内存泄漏问题类似,我发现有关 UIViewController 类实例的类似问题。使用 UIImagePickerController 的推荐方法是创建一次实例并在应用程序的生命周期内保留它,尽管这会占用您在其他地方可能需要的内存。

我正在处理的情况涉及 UIViewController 类的 2 个实例。启动时,创建第一个实例并将其视图添加到另一个“主”UIViewController 类,该类是 MainWindow.xib 的一部分。在第一个实例上是一个“信息”按钮,当点击该按钮时,将切换到 UIViewController 类的新实例(如果尚未创建)。 “主” UIViewController 使用通常的翻转动画来管理这种切换。基本设置可以在 Dave Mark 的“Beginning iPhone Development: Exploring the iPhone SDK”一书中看到。

出现的问题是,一旦第一次点击“信息”按钮,内存就会分配给新的第二个 UIViewController 实例,直到应用程序结束才释放。由于此信息视图上的元素数量众多,一旦实例化,它就会使用大约 1MB 的内存,并将其视图添加到超级视图中。任何持续销毁和重新创建此实例的尝试都会导致内存泄漏,类似于您尝试对 UIImagePickerController 类的实例执行相同操作时存在的内存泄漏。我怀疑这两个类的根本原因是一样的。

我的问题的症结在于在我允许用户使用相机拍照之前需要释放尽可能多的内存。然而,一旦用户拍照并且他们第一次看到生成的图像,他们就可以点击第一个 UIViewController 实例上的“信息”按钮。一旦被点击,“主” UIViewController 会移除现有 UIViewController 的视图并将其替换为信息屏幕的视图。信息屏幕有一个“返回”按钮来切换视图。但是,一旦用户离开信息屏幕并选择用相机拍摄另一张照片,分配给信息屏幕的内存仍在内存中。

UIImagePickerController 类在处理 2 兆像素图像时临时使用了将近 15-18MB,然后释放其内部引用并调用“imagePickerController:didFinishPickingImage”委托。一旦通过信息按钮创建了第二个 UIViewController 实例,然后用户选择拍摄另一张照片,我就会遇到内存不足的警报。

在我的情况下,无论您是否一遍又一遍地点击信息按钮,从技术上讲,内存都不会泄漏,但由于您无法控制的有关 iPhone(Safari 等)后台进程的其他问题,在使用相机等设备时,您必须尽可能多地释放内存。

关于如何干净地创建和销毁 UIViewController 类的实例以防止内存泄漏的任何建议?

【问题讨论】:

    标签: iphone memory-management camera


    【解决方案1】:

    您是否正在从 NIB 加载第二个视图控制器?如果是这样,您需要检查您是否正确释放了相关的内存。

    这是典型的基于 NIB 的视图控制器在我的项目中的样子。

    SomeViewController.h

    @interface SomeViewController : UIViewController {
        UILabel *someLabel;
    }
    
    @property (nonatomic, retain) IBOutlet UILabel *someLabel;
    
    @end
    

    SomeViewController.m

    @implementation SomeViewController
    
    @synthesize someLabel;
    
    - (void)dealloc {
        // Release our retained IBOutlets
        self.someLabel = nil;
        [super dealloc];
    }
    
    @end
    

    【讨论】:

    • 为什么在 dealloc 方法中使用 self.someLabel = nil 而不是 [someLabel release]?一样吗?
    • 不完全一样。 self.someLabel = nil 将向对象发送释放,然后将 nil 分配给属性。自己向对象发送释放不会将属性设置为 nil,您必须自己完成所有操作。我总是使用[_iVar release], _iVar = nil;,因为我没有将每个实例变量声明为属性。
    【解决方案2】:

    减少内存使用的一种方法是将图像调整为您想要的任何大小(当然,除非您想要 320x480 图像)。这对我来说很有帮助。

    您所说的第二个视图控制器是否发生了变化?如果不是,那么最好将其设为单例并使用相同的实例。您可以随时更改视图控制器使用的值。 This article 解释了如何创建单例对象(使用代码)

    Another article here 展示了单例类的使用(虽然与您的用例不同,但它将阐明如何使用单例)

    我建议也为 UIImagePickerController 创建一个单例对象。

    【讨论】:

      【解决方案3】:

      您的所有权链中有任何循环吗?比如:

      @interface FirstViewController: UIViewController {
        SecondViewController *secondViewController;
      }
      @end
      
      @interface SecondViewController: UIViewController {
        FirstViewController *firstViewController;
      }
      @end
      

      如果你在丢弃这些视图控制器时没有明确打破这个循环,它们就会泄漏。

      另外,我相信您有责任在不再需要时释放从 nib 文件加载的所有顶级对象。

      【讨论】:

      • 你如何明确打破循环?
      • 通过让 FirstViewController 实例显式执行 [secondViewController release]; secondViewController = 无; (或相反)在您知道要丢弃它们的应用程序中。
      • 我可以将这两行代码放在两个控制器的 dealloc 方法中吗?这样可以吗?
      • 不,这就是问题所在——dealloc 永远不会被调用。在丢弃配对的控制器之前,您将它们放入某个更高级别对象(如选项卡栏控制器或应用程序委托)调用的方法中
      【解决方案4】:

      也许您可以在转换到信息视图之前保存图像。保存后,释放图像,然后过渡到信息视图。如果用户返回,则从文件夹中加载图像。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-28
        相关资源
        最近更新 更多