我很难理解Swift
中关闭中真正发生的事情,并希望有人能帮助我理解。
class MyClass {
func printWhatever(words: String) {
print(words)
}
func doWhatever() {
dispatch_async(...) {
//why self
self.printWhatever("Hello")
}
}
}
在self.printWhatever("Hello")
行,为什么我必须使用self
? xCode
总是告诉我必须这样做,但我不确定为什么。所以,我的问题是闭包中究竟存储了什么。我知道一个闭包捕获周围的上下文。但是多少钱?是否捕获了MyClass
的实例?
答案 0 :(得分:3)
这是一个清晰的问题。只要您使用没有显式收件人的方法或属性名称,就会隐式将其发送到self
。但是在匿名函数中,你必须明确这个事实。如果你要说
printWhatever("Hello")
...您可能没有意识到您隐含地捕获self
。所以你可能没有意识到,如果这个匿名函数在self
的某个地方itself to be stored,你可以结束一个可怕的保留周期。因此,编译器强制您明确地说出self
,以便您了解自己行为的含义。
这方面的证据是,在某些情况下,不必须在匿名函数中说self
。考虑一下:
func printWhatever(words: String) {
print(words)
}
func doThis(f:()->()) {
f()
}
func doWhatever() {
doThis {
self.printWhatever("Hello") // self is required
}
}
在上面,必须说self
,因为编译器无法保证可能不会发生保留周期。但是现在看看如果我们添加@noescape
属性会发生什么:
func printWhatever(words: String) {
print(words)
}
func doThis(@noescape f:()->()) { // *
f()
}
func doWhatever() {
doThis {
printWhatever("Hello") // ok!
}
}
@noescape
属性保证传递的函数将立即执行而不存储。因此不再需要self
,因为不会发生保留周期。
就个人而言,我总是在任何我被允许的地方说self
。我建议你这样做。
注意:语言更改proposal为rejected,拒绝的理由之一就是我给出的一个:
在潜在转出的闭包中使用
self.
的要求是保留周期潜力的有用指标
答案 1 :(得分:1)
是否捕获了MyClass的实例?
是
答案 2 :(得分:1)
self
来捕获要发送消息的对象的实例。没有它,编译器不知道发送消息的人。
注意有时将self
放入clojure会导致引用循环,基本上捕获的对象永远不会被释放,在这种情况下你应该在clojure中创建一个捕获列表并指定一个不同的内存管理,如{{ 1}}或unowned