【问题标题】:Correctly handle didReceiveMemoryWarning正确处理 didReceiveMemoryWarning
【发布时间】:2012-05-03 10:08:33
【问题描述】:

我的一个UIViewController 有几个子视图控制器。它们是在界面构建器中构建的,通过将NSObject 拖到左侧的“对象”部分,然后将我自己的SpecialViewController 作为“自定义类”放入。通过此设置,在viewDidLoad 上,我将准备好我的视图和控制器。以下屏幕截图建议了工作流程:

在我的实现中,我有:

@interface ParentController : UIViewController
{
     SpecialViewController *svc;
}
@property (nonatomic, retain) IBOutlet SpecialViewController *svc;

据我了解,在didReceiveMemoryWarning 期间,我应该释放自己的资源。然后在viewDidUnload 期间将IBOutlets 设置为nil。

在模拟器中模拟低内存时出现崩溃,调试器在SpecialViewControllerdidReceiveMemoryWarning 处暂停(其主体只是[super didReceiveMemoryWarning];),并出现错误EXC_BAD_ACCESS (code=1, address=0xe0000008)。此时父控制器是不可见的,因此可以安全释放。

父控制器在didReceiveMemoryWarning 中也只包含[super didReceiveMemoryWarning];。我在两个班级都试过 niling IBOutlets。它没有帮助。

知道为什么会这样吗?

我的目标是带有 ARC 的 iOS 4 和 5。 SpecialViewControllerUITableViewController 的子类。

通过追踪发现ParentController didReceiveMemoryWarningSpecialViewController之前被调用。

【问题讨论】:

  • 释放对象和设置对象为零不相等。如果你发现内存警告,你必须释放 unused 资源。先尝试[svc release]
  • @Feo,嗯...我正在使用 ARC。我确实释放了未使用的资源。这些是我在自己的班级中管理的,对吗?
  • 你在self.scv=nil吗?
  • @JackyBoy,是的,我很肯定我这样做了。
  • 你应该在deallocviewDidUnload 中释放并分配出口到 nil .. 你在这样做吗?

标签: iphone objective-c ios cocoa-touch memory-management


【解决方案1】:

您似乎在此处的视图控制器中有一个视图控制器。您选择创建这样的课程有什么特别的原因吗?根据我的经验,每个 UIViewController 都应该是一个单独的子类。基于您的错误出现在didReceiveMemoryWarning 的事实,我认为问题出在其他地方。可以分享一下这个 View Controller 的初始化代码吗?

如果您正在尝试 UIViewController Containment 之类的操作,您可能应该查看涵盖此过程的 WWDC 主题。

【讨论】:

  • 我不知道这是一种奇怪的方法。 initWithNibName 方法除了调用 super 之外什么也没做。我记得在某处看到过这种方法,但现在无法真正获得链接。之所以这样设计,是因为 UI 有 3 个不同的表格视图,尽管它们不会同时显示。设计不好?
  • 是的,很可能是一个糟糕的设计。 1 个 UIViewController 中包含 3 个 UITableViews 怎么样?以编程方式在 3 个 UITableView 中的 2 个上切换 hidden 属性以显示正确的一个。
  • 你的意思是我应该在不启动 3 UITableViewControllers 的情况下这样做?只是通过我自己的代表单独管理它们?啊,我刚收到。我不应该使用额外的控制器。我只需要代表。谢谢你。我会修改我的代码,并希望很快接受你的回答。
  • 完美!我什至会使用 UIViewController 而不是 UITableViewController。不确定 UITableViewController 是否支持多个 UITableView。如果我能提供更多帮助,请告诉我。
【解决方案2】:

更新 iOS > 6.0:

视图不再在内存不足的情况下被清除,因此这个方法永远不会被称为[1]


视图控制器的didReceiveMemoryWarning 默认实现会释放他们的视图;您的责任只是发布在 viewDidLoadloadView 中创建的任何其他视图,以及对 IBOutlet 子视图的任何强引用。

你有一个对另一个视图控制器的强引用,当视图再次可见时,不会重新创建。您应该使用didReceiveMemoryWarning 来释放您的sec 实例变量;相反,依靠SpecialViewControllerdidReceiveMemoryWarning 实现来处理释放它的视图。

在实践中,我使用didReceiveMemoryWarning 发布我的主视图(self.view)并使用viewDidUnload 发布在viewDidLoad 中创建的任何内容。我发现方法名称及其用途的平衡很直观。如果你在viewDidLoad 中创建了一些东西,请在viewDidUnload 中发布它。

【讨论】:

  • 实际上,如果我不为零 IBOutlets,它会以同样的方式崩溃。我认为 niling 过程只是为了保护我自己的代码。理论上没有必要,对吗?但我的观点是控制器嵌入在 .xib 中。我不是在viewDidLoad 中创建它们。
  • 它们被 nil'd out,以便您释放尽可能多的内存(设置为 nil 会释放任何先前的实例)。由于您的目标是 iOS 4,因此您没有将弱引用归零,因此很可能在释放变量时未将其引用设置为 nil。你确定你没有在视图控制器中释放svc 吗?你在任何地方使用NSNotificationCenter 吗?我已经看到这在 iOS 4 中也会导致问题。
  • 在ARC下加上对象是在.xib中创建的,我想我实际上不能释放它。我不能叫释放。但就像我说的,不管它是否被 nil'ed 都是一样的。在didReceiveMemoryWarning 中什么都不做会崩溃。它还没有到达viewDidUnload
  • 在 ARC 下将变量设置为 nil 仍然会释放对象。请记住,您不是在 didReceiveMemoryWarning 中“什么都不做”,而是在调用 super,它(与 UIViewController 方法的其他一些默认实现不同)做了一些事情:它释放了您的视图。
  • 但是...这是retained 属性。我知道编译器会自动释放它。事实并非如此。我没有否定它。但是如果[super didReceiveMemoryWarning]选择放开,我也阻止不了可以吗?
猜你喜欢
  • 2015-03-19
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 2015-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多