为啥使用弱指针进行委托?

Posted

技术标签:

【中文标题】为啥使用弱指针进行委托?【英文标题】:Why use weak pointer for delegation?为什么使用弱指针进行委托? 【发布时间】:2011-12-09 17:03:47 【问题描述】:

我不明白为什么用弱指针定义一个委托是正确的:

@property (nonatomic,weak) id delegate;

我不明白为什么不需要保留对委托的引用...我不希望我用作委托的对象被释放...因此,我更喜欢使用强参考不弱!

在许多情况下,委托与将创建我的类的实例的对象相同,在这种情况下,创建弱引用将是避免保留循环的一个很好的解决方案......但是如果我选择一个完全不同的对象怎么办作为代表?

我搜索了有关堆栈溢出的其他问题,但找不到可以帮助我完全理解这种情况的内容。

【问题讨论】:

Why are Objective-C delegates usually given the property assign instead of retain? 的可能重复项 @BarryWark 为什么?我要求弱...不分配。肯定是相似的,但它不是同一个论点。 在这种情况下,weakassign,另外还有一个好处是,当委托被解除分配时,引用将为零。在以前的运行时,委托必须在解除分配之前将自己作为委托移除,否则它将留下一个悬空指针。参考问题的答案仍然可以回答您的问题。 @BarryWark 和你链接我的答案谈到 A 创建 B 并将自己指定为 B 的代表的 2 个对象之间的直接委托。我要求一个不同的环境......即 A 创建B 和 C 是 B 的代表。 新的内存管理技术,新的最佳实践,我不认为这是骗人的。 【参考方案1】:

对象弱保留其委托的原因是为了避免保留循环。想象以下场景:对象a 创建b 并保留它,然后将自己设置为b 的委托。 a 由其所有者释放,留下一个包含 ab 的保留循环。这实际上是一个非常常见的场景。考虑一个视图控制器,它拥有一个视图并充当该视图的委托。在这种情况下,视图不应该保留控制器——作为适当的 MVC 架构的主体并防止保留循环。

【讨论】:

谢谢,但在这样的情况下它如何相关:A 创建 BB 作为代表 C @Barry Wark - 只是好奇,“...,离开 ab 保留周期...”是什么意思?您还在您的场景中声明视图拥有特定视图并充当委托,并且视图不应保留控制器。我对你的意思有点困惑,愿意进一步解释一下吗? @MatterGoal 在您询问的情况下,确实可能没有必要弱化代表。如果您确定第三个对象不会创建保留循环,那么请继续这样做。但是拥有这些知识会引入耦合。您通常不会针对特定案例进行编码,而是针对一般案例进行编码,在这种情况下成为未来证明的最佳实践是弱持有委托。【参考方案2】:

虽然保留周期是一个有效的问题,但弱引用的原因更多地与苹果关于如何将委托模式与 uikit 和其他开箱即用的元素一起使用的观点相关,此处解释:

http://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html

具体来说: “委托的主要价值在于它允许您在一个中心对象中轻松自定义多个对象的行为。”

如果委托处理管理多个对象的委托任务,则这些对象不需要保留委托,也不应承担解除分配委托的责任,因为它可能被其他对象使用。弱引用强制执行委托的管理不是委托人责任的概念。

目标 c 中的一个示例是一个委托用于多个表视图,例如在使用表视图和带有 uisearchbar 的 searchdisplaycontroller 时。 Apple 的示例使用控制器作为委托,但在对主表视图和搜索结果表视图都使用一个自定义委托时,推理仍然成立。该自定义委托可能会由您的控制器保留,以便提供给两个表视图。

这与在其他语言中引用的基本委托模式根本不同,在其他语言中委托通常由委托人创建,并且每个实例都可以管理自己的委托实例。

【讨论】:

这对我来说是最好的答案——但最好理解不包括的缺点——这意味着什么?错误/缓慢的体验?【参考方案3】:

这是为了避免保留循环。 Apple 在advanced memory management 上提供了一份内容丰富的指南,解释了这种情况以及如何最好地处理它。在 ARC 中,它们现在被称为强参考循环,在 Transitioning to ARC Release Notes 中进行了解释。

以前你会像这样为委托定义一个属性,

@property (nonatomic, assign) id delegate;

但是在 ARC 中,你可以这样定义它,

@property (nonatomic, unsafe_unretained) id delegate;

或者,比如你有一个名为<MyObjectDelegate>的协议,你也可以这样定义委托,

@property (nonatomic, weak) id <MyObjectDelegate> delegate;

换句话说,在 ARC 中,如果你有一个协议,你可以声明一个委托 weak。否则,unsafe_unretained

【讨论】:

【参考方案4】:

通常的做法是,如果我们有两个相互持有引用的对象,我们将“父-子”关系中的“子”对象设为弱引用。 对于 iOS 中的委托模式,委托对象是父对象,因为没有委托对象就不需要委托调用者存在。例如,您有一个带有委托对象的句子对象,用于方法 sentenceShouldEnd。您的段落对象是您的句子对象的委托对象。显然,段落对象实际上是父对象,并且在您的句子对象中,您应该将委托作为弱引用。 就您而言,您将代表分配给自己,您的理解是错误的。我们永远不应该将委托分配给它自己。如果您觉得有必要聘请代理人为您买票,为什么还要自己买票?你说的是两个完全不同的概念。当您将委托对象定义为属性时,它在定义它的对象中使用了弱引用(比如说 A,即委托对象是 A 的属性)。当您初始化 A(假设在 B 中)时分配了代理,那么您很可能会将 A.delegate 分配给 self,实际上是 B。您看到这里的父子关系了吗?你在 B 中为 A 分配内存。你在 B 中持有 A。没有 B,A 不存在。你没有将委托分配给 A!!!!

【讨论】:

以上是关于为啥使用弱指针进行委托?的主要内容,如果未能解决你的问题,请参考以下文章

iOS学习——weak的应用场景

block的循环引用

翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用

GetFunctionPointerForDelegate 将委托中的 String^ 参数转换为啥?

使用 ARC 声明委托属性的推荐方法

弱委托和 .xib 文件