【问题标题】:So what's the deal with ARC and releasing properties/subviews on viewDidUnload那么 ARC 和在 viewDidUnload 上发布属性/子视图有什么关系
【发布时间】:2012-06-01 15:48:53
【问题描述】:

我仍在学习 iOS 开发,并且一直在研究各种教程和书籍。有些是 ARC 之前的,有些是 ARC。

在某些情况下,我们被告知要在 viewDidUnload 上释放 ViewController 的所有属性和子视图,但在某些情况下,我被告知不再需要这样做。

谁能给出明确的答案?在 iOS 5+ 中,是否必须做整体:

-(void)viewDidUnload
{
  [super viewDidUnload];
  self.photoViewCell = nil;
  self.photoImageView = nil;
  self.firstNameTextField = nil;
  self.lastNameTextField = nil;
}

... 还是没有?如果是这样,这仅适用于 UIView 的后代属性还是适用于 ViewController 的所有属性?

谢谢

【问题讨论】:

标签: ios automatic-ref-counting xcode4.3 objective-c-2.0


【解决方案1】:

所以每个视图都有多个所有者。当“所有者计数”(通常称为 retainCount)达到 0 时,该对象将被销毁。

在 iOS 5 中,我们现在有弱引用,这实质上意味着“不拥有这个对象”。

在 iOS 5 之前,您会在我们的头文件中看到

IBOutlet UILabel *myLabel;

这个标签被添加到 XIB 文件的视图中。在这种情况下,myLabel 有 2 个所有者:它是超级视图(XIB 文件中的视图)和视图控制器(通过拥有 IBOutlet)。当 viewDidUnload get 被调用时,视图控制器的视图已经被释放,因此它对 myLabel 的所有权消失了。所以此时 myLabel 只有 1 个所有者,即视图控制器。所以我们需要在 viewDidLoad 中释放它,以确保它没有任何所有者,因此被销毁了。

在 iOS 5 中,您会经常看到这种情况

__weak IBOutlet UILabel *myLabel

这是说我们不希望视图控制器成为 myLabel 的所有者。所以唯一的所有者是视图控制器的视图。所以当 viewDidUnload get 被调用时,视图控制器的视图已经被释放,因此它对 myLabel 的所有权也被释放了。在这种情况下,myLabel 现在没有所有者并且它的内存被释放。不需要 self.myLabel = nil;在那里。

因此,对于 iOS 5,建议将所有 IBOutlets 设为弱引用。有了这个,你甚至不需要实现 viewDidUnload,因为所有的内存都已经为你处理好了。

但即使您使用的是 iOS 5,如果您的 IBOutlets 不是弱引用,您将需要 viewDidUnload 中的代码。

【讨论】:

  • Apple 建议您尽可能多地使用 @properties,这样您就不会在使用 getter 和 setter 时遇到麻烦。 - 顺便说一下 -
  • 感谢您的精彩解释...到目前为止,我一直在为 IBOutlets 使用 strong 引用,这可能是我发现内存泄漏的原因。你能解释一下我什么时候应该使用强引用吗?
  • 只是为了突出我的问题...查看 iOS 学徒教程 - 在其中一个示例应用程序中,所有 IBOutlet 属性都是 strong :/ 有很多相互矛盾的信息
  • 下面我的答案要好得多,做得好!重要的是要记住何时调用 viewDidUnload - 仅当视图控制器仍然存在时(即在导航堆栈中,但不可见)但您处于内存不足的情况。并且@bodacious - 强大的出口不会给你这样的内存泄漏,但如果你不在 viewDidUnload 中将它们归零,你可能会遇到麻烦(见我的回答)
  • iOS 学徒教程,是通过苹果的吗?我想不出很多次你会想要一个对 IBOutlet 的强引用。一个奇怪的假设情况。假设您有一个带有 2 个选项卡的 UITabBarController。当您在标签 #1 上时,标签 #2 的视图可以被卸载(假设它首先被加载)。比如说,如果你有一个 UITextField,其中包含一些尚未“提交”的文本,那么对该 UITextField 进行强引用将确保在视图控制器的视图被销毁时它不会被销毁。不过,您需要确保您的记忆力适合该文本字段。
【解决方案2】:

viewDidUnload 与自动或其他保留计数无关。当由于内存压力而卸载视图时将调用此方法,这意味着您还应该 nil(并释放,非 ARC)您持有强引用的视图元素。不这样做可能意味着您的应用程序在内存压力下没有释放足够的内存,这可能导致它被操作系统关闭。

【讨论】:

    【解决方案3】:

    如果您的应用值得,您可以使用 viewDidUnload 来管理内存。

    但不要这样做

    myInstanceVariable = nil;
    

    您失去了对变量值所在的内存位置的引用。

    = nil 不会释放内存。不过,您的对象必须被释放。因此使用了retainCount 和retain/release。

    如果您在 viewDidUnload 中将对象设为 nil,则无法在 dealloc 中释放!注意!!!

    如果你知道你做了什么,你就可以在 viewDidUnload 中释放和归零你的对象。

    弧:

    使用ARC,你不能手动释放,即使我认为你不能这样做。 ARC 负责这一点。 只需尽可能多地使用 @properties 和 (weak/strong) 属性,让 getter 和 setter 为您完成工作。您也可以在 .m 文件中声明 @properties(就像在类扩展中一样)。

    简单的规则:强的对象你想拥有,弱的对象,你不想迷失在一个保留周期和持有所有权。 ARC 在几乎所有情况下都会完成其余的工作。例如,对代表使用弱。

    nil 对象,在你确定的地方,你不会向它们发送消息,否则不要。

    【讨论】:

    • 在 ARC 下,如果该指针是对象的最后一个所有者,则设置变量 = nil 将释放内存。
    • viewDidUnload 不是 viewDidLoadinit 的对应项。如果您尝试在 MRR 下释放内存,它通常会泄漏,因为除非出现内存警告,否则不会调用 viewDidUnload
    猜你喜欢
    • 2012-08-19
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    相关资源
    最近更新 更多