为什么在依赖于 self 存在的 block 中需要指定 [unowned self]?

5

我希望self是非空的,并且我确信在块执行期间它将是非空的。那么为什么要明确指定[unowned self]?

object.executeBlock {
    date = self.lastModified
}

vs

object.executeBlock { [unowned self] in
    date = self.lastModified
}

编辑: 好吧,我得到了一些反对意见,那么让我们再试一次。问题是这样的:假设我有一个问题。我的问题是,我想要避免引用循环。我有两个选择。我可以使用 [unowned self] 或者我可以使用 [weak self]。因此,我的问题是:从这两个选项中,为什么我会选择 [unowned self]?为什么不总是选择 [weak self]?

5个回答

5
"The Language Guide指出,如果闭包和包含对象相互引用且将同时被销毁,则应使用unowned。这可能是为了避免在即将dealloc的对象中安全地nil掉弱引用的成本。因此,[unowned self]使self成为一个隐式解包的可选项,方便您不必自己解包,但如果它实际上为nil,则存在崩溃的风险。"

http://www.russbishop.net/swift-capture-lists


3

只有在存在强引用循环的情况下,你才需要使用[unowned self][weak self]。强引用循环是指所有权循环的一种情况,其中对象最终彼此拥有(可能通过第三方),因此它们永远不会被销毁,因为它们都确保彼此存在。

你是否存在强引用循环?


嗨,Arsen,感谢您的回复。但恐怕这并没有完全回答我的问题。类似的问题可以在这里找到,那个问题的答案也未能真正回答“为什么使用unowned self”的问题。我只想知道具体需要使用“unowned self”而不是“weak self”。这里的答案指出,如果我们使用weak,则self是一个可选项。我可以接受这一点……但为什么要使用“unowned self”呢?具体地说,就是“只有”unowned self。https://dev59.com/_mAf5IYBdhLWcg3wwkwV - user1951992
@robdashnash:你的问题并没有涉及到unownedweak之间的区别,而是关于unowned和什么都不用之间的区别,这个答案回答了你的问题。至于为什么要使用unowned而不是weak,原因是你也可以使用weak self,但是那样的话,self将会是可选类型,你必须以某种方式对其进行解包,而如果你知道self仍然存活,那么unowned self更方便,因为self是非可选类型,所以你可以在不显式解包的情况下使用它。 - newacct

2

我在其他地方回答过这个问题。以下是要点:

如果闭包中的self可能为nil,请使用[weak self]。

如果闭包中的self永远不会为nil,请使用[unowned self]。

如果你在使用[unowned self]时遇到了崩溃,我猜测self在该闭包中某一时刻为nil,这就是你必须改用[weak self]的原因。

我真的很喜欢手册上关于在闭包中使用strong、weak和unowned的整个部分:

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html


0
在闭包中使用self时,如果可能出现nil的情况,你必须使用weak语义(否则会导致崩溃)。
如果你可以确定self永远不会是nil,那么你可以选择指定:"choose",意思是两个都是正确的且可行的。可以认为其中一个比另一个更加“正确”,因为两种语义都满足要求,但一个更加具体。
有两个原因你可能想要指定unowned而不是self
  • 方便性
  • 文档说明
使用unowned引用将更加方便,因为它不需要解包。由于编译器可能不需要为安全释放分配多余的清理代码,因此它也可能更有效率。
就文档而言,你正在对程序认为是真实的事情做出一种断言。如果该假设(假设它是有效的)被违反,你可能希望以崩溃的形式发现这一点。
随后,这也可能使变量的使用更加轻松:您考虑并记录了需要预先存在的原因,然后每次使用它时,您都不必再花费更多的精力去思考“如果没有它该怎么办?”。
可以说,使用 let 绑定或 guard 语句也可以实现后者。

0
为什么要使用 [unowned self]?
self 指向对象,对象有 executeBlock,而 executeBlock 又指回 self,从而创建了一个内存循环。
然而,当你使用 [unowned self] 时:系统不会将 self 保留在内存中以使闭包工作。它会假设在执行闭包时 self 总是存在的。如果出现问题,不会有未定义的行为或其他类似情况,但你的应用程序会崩溃,因为这是运行时错误。
这是由斯坦福大学 iOS 开发教师 Paul Hegarty 解释的。

我很惊讶有多少人误读了这个问题。我不是在问为什么我要避免保留循环,因为我知道为什么那很重要。我也同意,Paul Hegarty是众神之神。我所问的是,为什么我会选择特定的无主self,当我还有“弱”时。无论如何,我已经回答了自己的问题。请查看我在此线程中开始的答案:“语言指南声称…” - user1951992

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