IBOutlet和其他属性使用weak还是strong?

31

我已将我的项目转换为ARC,但我不明白我是否必须在IBOutlets中使用strongweak。Xcode会这样做:在界面构建器中,如果我创建一个UILabel,并将其与助理编辑器连接到我的ViewController,它会创建以下内容:

@property (nonatomic, strong) UILabel *aLabel;

它使用了strong,但我在RayWenderlich网站上读到一篇教程,它说:

但是对于这两个特定属性,我有其他计划。我们将它们声明为weak,而不是strong

@property (nonatomic, weak) IBOutlet UITableView *tableView;
@property (nonatomic, weak) IBOutlet UISearchBar *searchBar;

弱引用是所有outlet属性的推荐关系。这些视图对象已经是视图控制器视图层次结构的一部分,不需要在其他地方保留。声明你的outlets为weak的最大优点是它节省了编写viewDidUnload方法的时间。

目前我们的viewDidUnload看起来像这样:

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.tableView = nil;
    self.searchBar = nil;
    soundEffect = nil;
}

现在你可以将其简化为以下内容:

- (void)viewDidUnload
{
    [super viewDidUnload];
    soundEffect = nil;
}

使用weak而非strong,并且在videDidUnload中删除对nil的赋值操作。Xcode会使用strong,应该在viewDidUnload中使用self... = nil

我的问题是:我何时需要使用strong,何时需要使用weak?我想在iOS 4上部署,那么何时需要使用unsafe_unretain?有人能够用简单的教程详细解释一下何时使用ARC中的strongweakunsafe_unretain吗?

2个回答

69

一个经验法则

当父对象持有子对象的引用时,应该使用强引用(strong reference)。当子对象持有父对象的引用时,应该使用弱引用(weak reference)不安全的未保留引用(unsafe_unretained reference)(如果前者不可用)。典型的场景是处理代理。例如,UITableViewDelegate不会保留包含表视图的控制器类。

enter image description here

这里是一个简单的模式,用于展示主要概念。
首先假设A、B和C都是强引用。特别地,C有一个对其父对象的强引用。当obj1被释放(在某个地方),A引用不再存在,但由于obj1和obj2之间存在循环引用,因此会出现内存泄漏。从保留计数的角度来说(仅用于解释目的),obj1的保留计数为2(obj2有一个强引用),而obj2的保留计数为1。如果释放了obj1,则它的保留计数现在为1,其dealloc方法不会被调用。obj1和obj2仍然存在于内存中,但没有任何人引用它们:内存泄漏
相反,如果只有A和B是strong引用,而C被称为weak,那么一切都很好。你没有泄漏。实际上,当obj1被释放时,它也释放了obj2。从保留计数的角度来看,obj1的保留计数为1,obj2的保留计数为1。如果obj1被释放,它的保留计数现在为0,它的dealloc方法将被调用。obj1和obj2将从内存中删除。
一个简单的建议:在处理ARC时开始考虑对象图。
关于你的第一个问题,处理XIBs时两种解决方案都是有效的。一般来说,当处理内存循环时使用“weak”引用。 关于XIBs文件,如果你使用“strong”,你需要在“viewDidUnload”中设置“nil”,因为如果你不这样做,在内存低的情况下,可能会导致意外泄漏。你不需要在“dealloc”中释放它们,因为ARC会为你完成。 相反,“weak”则不需要这样的处理,因为当目标对象被销毁时,这些值会自动设置为“nil”。不再有悬空指针。
如果你感兴趣,我真的建议你阅读Mike Ash的friday-qa-2012-04-13-nib-memory-management
关于你的第二个问题,如果你需要支持iOS 4,而不是使用“weak”,你必须使用“unsafe_unretained”。
在SO中有很多问题/答案。以下是主要问题:

当我使用ARC并针对iOS 4.0时,如何替换弱引用?

自动引用计数在Objective-C中不能防止或最小化哪些类型的泄漏?

使用ARC、生命周期限定符assign和unsafe_unretained

strong/weak/retain/unsafe_unretained/assign

更新

根据shaunlim的评论,在iOS 6开始,viewDidUnload方法已被弃用。在这里,我真的建议查看Rob的答案:iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?


你说,对于IBOutlet,如果我使用strong,我必须在viewdidunload中使用nil,在低内存情况下就不会有泄漏了。而对于weak,我不必在videwdidunlaod中使用nil,在低内存警告时,强引用和弱引用哪个更好? - Piero
一样的。使用weak可以让您节省手动编写代码(在您的情况下为两行)的时间。但是,Xcode会为您完成它。我的个人意见。我喜欢使用strong - Lorenzo B
刚看到这个,想指出viewDidUnload已经被弃用了。尽管如此,这仍然是一个非常有价值的答案! - shaunlim
@shaunlim非常感谢!我会根据您的评论更新答案。谢谢您。 - Lorenzo B

11

如果您要连接到IB中的对象,可以使用weak关键字来定义变量,因为在这种情况下,只要父视图存在,对象就会存在。这是因为父视图对其子视图有一个强引用。

如果您定义的指针是指向该对象的唯一指针,则应将其声明为strong。

如果您是注册开发人员,我强烈建议您观看WWDC11和WWDC12的视频。另一个很好的资源是斯坦福大学的iOS开发播客


WWDC12的视频已经发布了吗? - borrrden
是的,它们真的很快今年。 - dasdom
好的,但我不理解,我的问题涵盖了unsafe_unretain,但是对于IBOutlet,我解释得很清楚,为什么苹果要使用strong而不是weak呢?所以我应该跟随苹果?还是跟随raywenderlich教程中使用weak代码片段的方式? - Piero
我的猜测是,从某种意义上说,强引用更安全,因为除了作为子视图被父视图保留之外,插座还被保留“再次”。想象一下,在运行时编程地添加/删除一些子视图。通过具有强引用,已删除的子视图将持久存在(不会被释放)。作为交换,您必须在viewDidUnload中将强引用设置为nil。 - Nicolas Miari
另一方面,如果您在IB中设置了nib并且它永远保持不变(在运行时没有删除/重新添加子视图),那么弱引用就足够了(或者在iOS 5之前使用'unsafe_unretained)。 - Nicolas Miari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接