Swift,为什么类方法不需要闭包列表



If 函数本质上是闭包。为什么类的方法在引用 self 或闭包中的其他实例属性时不需要闭包列表。

幕后有[无主的自我]吗?例如:

class MyClass{
func myFunc(){
self.otherFunc()
}
func otherFunc(){
print()
}
}

myFunc中不会有一个参考循环吗?即,闭包指向 self,实例指向函数。两者都无法分配。

">

如果函数本质上是闭包。这不是真的。函数(和方法(与闭包不是一回事。函数的所有自由变量都未绑定。闭包绑定了它们的部分或全部自由变量(闭包在它们上面,这就是名称"闭包"的由来(。

"自由变量"是在函数范围之外定义的任何变量(包括其形式参数(。顶级函数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的值?我可能已经返回cx现在可能超出了范围。系统必须跟踪x(包括进行强引用,以便它不会解除分配(,它通过捕获它或"关闭x"来做到这一点,这增加了保留循环的可能性。所以在cx是有束缚的。它不是免费的。当你打电话给c()时,你不能通过它。

self在这里并不特别。这只是另一个变量。 闭合[weak self]也不特别。你也可以写[weak x][...]语法只是捕获列表。

闭包可能只在闭包保持活动状态时导致参考循环。考虑一下:

let foo = MyClass()
let bar: () -> () = { in
print(foo)
}

bar闭包包含对foo的引用,但是一旦没有任何东西引用bar,该引用就会消失。例如:

func f(foo: MyClass) {
let bar: () -> () = { () in
print(foo)
}
}

这不会创建参考循环,因为当f返回时,bar中的闭包会被破坏。同样,当您调用myFuncotherFunc时,您确实需要对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.closureself有很强的引用,selfself.closure有很强的引用。

最新更新