我试图尽可能多地挖掘这个主题,但我仍然有一些事情没有在我的脑海中安定下来,我将不胜感激得到澄清......所以我提出了几个问题。
- 编译器如何知道我必须在后台线程上添加@escaping,并以此强制我使用它?
- 使用@escaping需要付费吗?如果没有。.为什么不总是标记?如果我用@escaping标记闭包,即使我真的不需要它,会出什么问题?当我试图这样做时..我的代码没有问题,无论有没有@escaping的结果都保持不变。
- 使用捕获列表 [弱自我] [无主自我] 的成本是多少? 我知道它会制作该对象的副本,所以我想暂时它会占用更多内存,但在使用该结束时,该副本将从内存中删除。那么,使用它有更多的缺点吗?
简短回答
- 编译器使用不同的过程来分析代码。有很多关于大学编译器如何工作的讲座。所以很难给你一个正确的答案。
- 使用您需要的内容。很难评估这要花多少钱。@escaping和@no转义有不同的用例。
- 我没有看到缺点。使用弱是防止保留周期和内存泄漏的好方法。
解释
1:所以这个编译器到底是如何工作的,我真的不知道。但是,如果您想了解编译器通常如何工作,请阅读一些像这样的轻量级文章
在我看来,编译器将具有词法分析,语法分析和语义分析。因此,编译器将检测您是否需要转义。
2:闭包是 swift 中的一个概念,即"在事情完成时做事"。有关更多详细信息,请查看文档和此处
以下信息很大程度上基于这篇文章 什么是转义和非转义闭包
在 Swift 中,默认情况下@escaping 1 和 2 的闭包。由于 Swift 3 闭包是@no转义的。
@no逃逸的蝙蝠
当您在函数的参数中传递闭包时,在函数的主体被执行并返回编译器之前使用它。当函数结束时,传递的闭包将超出范围,并且在内存中不再存在。
简单地说,对于开发人员来说,这是舒适的内存处理,因为他什么都不关心。
@escaiping封口
对于@escaping闭包,有两种用例:
存储:当您需要将闭包存储在全局变量中时,属性或存在于调用函数过去内存中的任何其他存储将被执行并返回编译器。
异步执行:当您在发送队列上异步执行闭包时,队列将为您保留闭包的内存,将来可以使用。在这种情况下,您不知道何时会执行闭包。
来自苹果文档
闭包被称为转义函数,当闭包传递为 函数的参数,但在函数返回后调用。 [...]您可以在参数类型之前写入@escaping 表示允许关闭进行转义。
仅供参考:闭包标志着操作是异步的,并且在后台线程上不引人注目。
3:我认为使用它没有缺点。使用弱是防止保留周期和内存泄漏的好方法。当您获得稳定的应用程序时,您应该忽略潜在的成本。但我再说一遍:使用你需要的东西。对于内存泄漏,这是一件棘手的事情,通常很难找到。
有关委托和内存泄漏的真正答案,请参阅 https://stackoverflow.com/a/34566876/4420355。这篇文章中也有很多进一步的链接。如果您阅读它们,您将很好地/更好地了解内存泄漏将如何发生以及如何防止它们。
也检查一下这篇文章,它和你的 https://stackoverflow.com/a/46245943/4420355 有点相似
编辑为 3
发问 者:
我想我没做对......那么"捕获"是什么意思,就无主自我而言,它在幕后是如何工作的? 闭包如何在不拥有对象的情况下使用 self? 也许这个问题需要与堆栈溢出分开
灵感来自帖子示例 可以在其范围之外访问局部变量的内存吗?
你租一个酒店房间。你第二天早上退房,锁上门,但"忘记"归还钥匙。你偷了钥匙!没有备用钥匙。所以酒店房间是锁着的。酒店老板不能再租这个房间了。现在有很多客人偷了钥匙。有时每个房间实际上都是免费的,但上锁了。
有点幻想,房客是一个关闭。他租用房间(创建对房间实例的引用)。他睡在那里(异步操作)。他应该把钥匙还给他,但他没有。
在我的理解中,闭包并不拥有对象。它是实例的闭包和属性之间的引用。
苹果文档:
如果将闭包分配给 类实例的属性,以及该闭包的主体捕获 实例。发生此捕获可能是因为关闭的正文 访问实例的属性,例如 self.someProperty,或 因为闭包在实例上调用方法,例如 self.someMethod().在任一情况下,这些访问都会导致关闭 "捕捉"自我,创造强大的参考循环。
你可以用weak
或unowned
来解决这个强循环。在我的观点中,苹果用来解释weak
和unowned
之间区别的图像非常好:请参阅自动引用计数