如果函数基本上是闭包。为什么在关键字中引用self或其他实例属性时,类的方法不需要闭包列表。
幕后是否有[无主的自我]?例如:
class MyClass{
func myFunc(){
self.otherFunc()
}
func otherFunc(){
print()
}
}
myFunc中是否存在参考周期?即,闭包指向self,实例指向函数。两者都不能解除分配。
答案 0 :(得分:2)
闭包只能在闭合保持活动时引起参考循环。考虑一下:
let foo = MyClass()
let bar: () -> () = { in
print(foo)
}
bar
闭包含有foo
的引用,但一旦没有引用bar
,该引用就会消失。例如:
func f(foo: MyClass) {
let bar: () -> () = { () in
print(foo)
}
}
这不会创建引用循环,因为当f
返回时,bar
中的闭包被销毁。同样,当您调用myFunc
和otherFunc
时,您需要强引用self
(编译器确保您拥有它),但是因为您不再需要它功能,没有创建循环。
通常,闭包不会系统地创建引用循环,即使它是@escaping
。考虑Dispatch.async
:
class MyClass {
func foo() {
DispatchQueue.main.async {
print(self)
}
}
}
这不会实际上创建一个引用循环,因为即使闭包引用了self
一段时间,self
也没有引用闭包。
危险的情况就是这个:
class MyClass {
var closure: () -> ()
func f() {
self.closure = {
print(self)
}
}
}
这个实际上会创建一个参考周期:self.closure
强烈引用self
,self
强烈引用self.closure
答案 1 :(得分:2)
“如果功能基本上是封闭的。”事实并非如此。函数(和方法)与闭包不是一回事。函数的所有自由变量都是未绑定的。闭包已绑定了部分或全部自由变量(关闭它们,这就是“闭包”的名称来源)。
“自由变量”是在函数范围之外定义的任何变量(包括其形式参数)。顶级函数func f(x: Int)
有一个自由变量;当你调用它时,你必须传递一个参数。像{ f(1) }
这样的闭包没有自由变量。当你调用它时,你不会传递任何参数。
方法与函数一样,不捕获任何东西。它在执行时传递所有自由变量。例如,当您拨打电话object.doThis()
时,这与呼叫Type.doThis(object)()
相同。
class X {
func doThis() {}
}
let x = X()
x.doThis()
X.doThis(x)() // Same thing
X.doThis(x)
是一个返回函数的函数。这里没有魔力。在通话期间提供所有自由变量。没有捕获任何东西。 (在你描述的情况下,“自由变量”是self
,但这并没有改变任何东西。self
并不特别,除了它周围有一些语法糖。)
这与闭包不同:
let c = { x.doThis() }
c()
当我致电c()
时,它如何知道x
的价值?我可能已经返回c
,x
现在可能已超出范围。系统必须跟踪x
(包括制作一个强引用,因此它不会解除分配),并通过捕获它或“关闭x”来提高保留循环的可能性。因此,在c
中,x
受到约束。它不是免费的。致电c()
时,您无法通过。
self
在这里并不特别。这只是另一个变量。封闭中的[weak self]
也不是特别的。你也可以写[weak x]
。 [...]
语法只是捕获列表。