31

我已将我的项目切换到 ARC,但我不明白我是否必须使用strongIBOutlets weak。Xcode 这样做:在界面生成器中,如果创建一个UILabel例如,我将它与助手编辑器连接到我的ViewController,它会创建这个:

@property (nonatomic, strong) UILabel *aLabel;

它使用strong,而不是我在 RayWenderlich 网站上阅读了一个教程,上面写着:

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

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

Weak是所有出口属性的推荐关系。这些视图对象已经是视图控制器的视图层次结构的一部分,不需要保留在其他地方。声明你的 outlet 的一大好处weak是它可以节省你编写 viewDidUnload 方法的时间。

目前我们的viewDidUnload样子是这样的:

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

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

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

所以使用weak, 而不是,strong并在.videDidUnloadstrongself... = nilviewDidUnload

我的问题是:我什么时候必须使用strong,什么时候weak?我还想用于部署目标 iOS 4,所以我什么时候必须使用unsafe_unretain?任何人都可以通过一个小教程帮助我很好地解释我,什么时候使用strongweak以及unsafe_unretain使用 ARC?

4

2 回答 2

69

经验法则

当父对象具有对子对象的引用时,您应该使用strong引用。当子对象具有对其父对象的引用时,您应该使用一个weak引用或一个引用 unsafe_unretained(如果前者不可用)。一个典型的场景是当您与代表打交道时。例如, aUITableViewDelegate不保留包含表视图的控制器类。

在此处输入图像描述

这里有一个简单的模式来展示主要概念。

假设第一个 A、B 和 C 是strong引用。特别是,C 有一个strong对其父级的引用。当 obj1 被释放(某处)时,A 引用不再存在,但您有泄漏,因为 obj1 和 obj2 之间存在循环。就保留计数而言(仅用于解释目的),obj1 的保留计数为 2(obj2 对其有strong引用),而 obj2 的保留计数为 1。如果 obj1 被释放,它的保留计数现在为 1,并且它的dealloc方法没有被调用。obj1 和 obj2 仍然保留在内存中,但没有人引用它们:Leak

相反,如果只有 A 和 B 是strongrefs 并且 C 是合格的,因为weak一切都很好。你没有泄漏。事实上,当 obj1 被释放时,它也释放了 obj2。就保留计数而言,obj1 的保留计数为 1,obj2 的保留计数为 1。如果 obj1 被释放,则其保留计数现在为 0,并dealloc调用其方法。obj1 和 obj2 从内存中删除。

一个简单的建议:在处理 ARC 时开始考虑对象图。

关于您的第一个问题,当您处理 XIB 时,这两种解决方案都有效。通常weak,在处理内存周期时会使用参考。关于 XIBs 文件,如果你使用strong你需要设置nilviewDidUnload因为如果你不这样做,在内存不足的情况下,你可能会导致意外泄漏。你不会释放它们,dealloc因为 ARC 会为你做。 weak相反,不需要这种处理,因为当目标对象被销毁时,这些值会nil自动设置。不再有悬空指针。

如果您有兴趣,我真的建议您阅读Mike Ashfriday-qa-2012-04-13-nib-memory-management

关于你的第二个问题,如果你需要支持 iOS 4,而不是weak你必须使用unsafe_unretained.

在 SO 中有很多问题/答案。这里主要的:

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

Objective-C 中的自动引用计数不能防止或最小化什么样的泄漏?

使用 ARC、lifetime qualifier assign 和 unsafe_unretained

强 / 弱 / 保留 / unsafe_unretained / 分配

希望有帮助。

更新

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

于 2012-06-23T14:35:51.100 回答
11

您可以对通过 IBOutlets 连接到 IB 中的对象的对象使用弱,因为在这种情况下,只要超级视图存在,对象就会存在。这是因为父视图有一个指向其子视图的强指针。

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

如果您是注册开发者,我强烈建议您查看来自 WWDC11 和 WWDC12 的视频。另一个很好的资源是斯坦福的 iOS 开发播客。

于 2012-06-23T11:08:44.687 回答