我尽可能多地在这个问题上钻研,但我还有一些事情没有在头脑中解决,我会很感激得到澄清。所以我问了几个问题……
编译器如何知道我必须在后台线程上添加@escaping,并以此强制我使用它?
使用@escaping有成本吗?如果没有……为什么不一直标记?如果我用@escaping标记关闭,即使我真的不需要它,会发生什么错误?当我试图这么做的时候……我的代码没有问题,无论有没有@escaping,结果都是一样的。
使用捕获列表[弱自我][无主自我]的成本是多少?
我知道它复制了那个对象,所以我想暂时需要更多的内存,但在使用结束后,那个副本将从内存中删除。那么,使用它还有更多的缺点呢?

最佳答案

简短的回答
编译器使用不同的过程来分析代码。有很多关于大学编纂者如何工作的讲座。所以很难给你一个正确的答案。
使用你需要的。很难估计这要花多少钱。@转义和@no转义有不同的用例。
我看不出缺点。使用weak是防止零售周期和内存泄漏的好方法。
解释
1:所以这个编译器的工作原理我真的不知道。但是,如果您想了解编译器通常是如何工作的,请阅读一些轻量级的文章,如one
在我看来,编译器将进行词汇分析、语法分析和语义分析。因此编译器将检测您是否需要转义。
2:闭包是一个很快的概念,即你“在事情已经完成的时候做事情”。有关更多详细信息,请查看documentationhere
以下信息主要基于本文what-do-mean-escaping-and-nonescaping-closures-in-swift
在swift中,1和2个闭包默认为@escaping。因为Swift 3的关闭是“不逃跑”的。
@禁止越狱
当传递函数参数中的闭包时,在函数体得到执行并返回编译器之前使用它。当函数结束时,传递的闭包超出范围,在内存中不再存在。
简单地说,对于开发人员来说,这是一种舒适的内存处理,因为他什么都不关心。
@紧急关闭
对于@escaping闭包,有两个用例:
存储:当需要将闭包存储在全局变量、属性或调用函数过去内存中存在的任何其他存储中时,执行并返回编译器。
异步执行:当您在发送队列上异步执行闭包时,队列将在内存中为您保存闭包,以后可以使用。在这种情况下,您不知道什么时候执行关闭。
来自苹果文档
当闭包作为
函数的参数,但在函数返回后调用。
[…]可以在参数的类型之前将@escaping写入
表示允许关闭。
提示:闭包标志着一个操作是异步的,而不是在后台线程上强制执行的。
3:我看不出使用它的缺点。使用weak是防止零售周期和内存泄漏的好方法。当你得到一个稳定的应用程序时,你应该忽略潜在的成本。但我重复一遍:用你需要的。随着记忆的泄漏,这是一个棘手的事情,往往很难找到。
有关代理和内存泄漏的真正好的答案,请参阅https://stackoverflow.com/a/34566876/4420355。这篇文章中还有很多其他链接。如果你读了它们,你会更好地理解内存泄漏是如何发生的,以及如何预防它们。
再看看这篇文章,它有点像你的https://stackoverflow.com/a/46245943/4420355
编辑为3
提问者:
我想我没弄好……那么,“捕获”是什么意思呢?它是如何在幕后以无主的自我来工作的?闭包如何在不拥有对象的情况下使用self?也许这个问题需要单独到stackoverflow
灵感来源于帖子Can a local variable's memory be accessed outside its scope?
你租了一间酒店房间。你第二天早上退房,锁上门,但“忘了”把钥匙还回去。你偷了钥匙!没有备用钥匙。所以旅馆房间是锁着的。旅馆老板不能再租这个房间了。现在有很多客人偷了钥匙。有时,每个房间实际上都是免费的,但都是锁着的。
有点幻想,房客就要关门了。他租用房间(创建对房间实例的引用)。他睡在那里(异步操作)。他应该把钥匙还给我,但他没有。
据我所知,闭包并不拥有对象。它是一个实例的闭包和属性之间的引用。
苹果文档:
如果将一个闭包分配给
类实例的属性,该闭包的主体捕获
实例。这种捕获可能是因为关闭的主体
访问实例的属性,例如self.someproperty,或
因为闭包在实例上调用了一个方法,例如
self.somemethod()。无论哪种情况,这些访问都会导致
“捕捉”自我,创造一个强大的参考周期。
您可以使用weakunowned来解决这个强循环。在我的观点中,苹果用来解释weakunowned之间的区别的图片真的很好:参见Automatic Reference Counting

08-19 11:55