Swift,为什么 class 方法不需要闭包列表
Swift, why don't class methods need closure lists
如果函数本质上是闭包。为什么 class 的方法在闭包中引用自身或另一个实例 属性 时不需要闭包列表。
背后是否有一个[无主的自己]?例如:
class MyClass{
func myFunc(){
self.otherFunc()
}
func otherFunc(){
print()
}
}
myFunc 中不会有引用循环吗?即,闭包指向自身,而实例指向函数。两者都无法解除分配。
只有当闭包保持活动状态时,闭包才可能导致引用循环。考虑一下:
let foo = MyClass()
let bar: () -> () = { in
print(foo)
}
bar
闭包包含对 foo
的引用,但一旦不再引用 bar
,该引用就会消失。例如:
func f(foo: MyClass) {
let bar: () -> () = { () in
print(foo)
}
}
这不会创建引用循环,因为当 f
returns 时,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
有强引用self.closure
.
"If functions are essentially closures." 这不是真的。函数(和方法)与闭包不同。函数的所有自由变量都是未绑定的。闭包绑定了它们的部分或全部自由变量(对它们关闭,这就是名称 "closure" 的来源)。
A "free variable" 是在函数范围之外定义的任何变量(包括其形式参数)。顶层函数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)
是一个函数,returns是一个函数。这里没有魔法。在调用期间提供所有自由变量。什么都没有被捕获。 (在您描述的情况下,"free variable" 是 self
,但这并没有改变任何东西。self
并不特别,除了它周围有一些语法糖。)
这与闭包不同:
let c = { x.doThis() }
c()
当我调用c()
时,它是如何知道x
的值的?我可能已经返回 c
并且 x
现在可能超出了范围。系统必须跟踪 x
(包括进行强引用,因此它不会解除分配),并且它通过捕获它来做到这一点,或者 "closing over x" 这会增加保留循环的可能性。所以在c
中,x
是绑定的。它不是免费的。调用c()
.
时不能传
self
在这里并不特殊。这只是另一个变量。 [weak self]
在闭包中也不是特别的。你也可以写 [weak x]
。 [...]
语法只是捕获列表。
如果函数本质上是闭包。为什么 class 的方法在闭包中引用自身或另一个实例 属性 时不需要闭包列表。
背后是否有一个[无主的自己]?例如:
class MyClass{
func myFunc(){
self.otherFunc()
}
func otherFunc(){
print()
}
}
myFunc 中不会有引用循环吗?即,闭包指向自身,而实例指向函数。两者都无法解除分配。
只有当闭包保持活动状态时,闭包才可能导致引用循环。考虑一下:
let foo = MyClass()
let bar: () -> () = { in
print(foo)
}
bar
闭包包含对 foo
的引用,但一旦不再引用 bar
,该引用就会消失。例如:
func f(foo: MyClass) {
let bar: () -> () = { () in
print(foo)
}
}
这不会创建引用循环,因为当 f
returns 时,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
有强引用self.closure
.
"If functions are essentially closures." 这不是真的。函数(和方法)与闭包不同。函数的所有自由变量都是未绑定的。闭包绑定了它们的部分或全部自由变量(对它们关闭,这就是名称 "closure" 的来源)。
A "free variable" 是在函数范围之外定义的任何变量(包括其形式参数)。顶层函数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)
是一个函数,returns是一个函数。这里没有魔法。在调用期间提供所有自由变量。什么都没有被捕获。 (在您描述的情况下,"free variable" 是 self
,但这并没有改变任何东西。self
并不特别,除了它周围有一些语法糖。)
这与闭包不同:
let c = { x.doThis() }
c()
当我调用c()
时,它是如何知道x
的值的?我可能已经返回 c
并且 x
现在可能超出了范围。系统必须跟踪 x
(包括进行强引用,因此它不会解除分配),并且它通过捕获它来做到这一点,或者 "closing over x" 这会增加保留循环的可能性。所以在c
中,x
是绑定的。它不是免费的。调用c()
.
self
在这里并不特殊。这只是另一个变量。 [weak self]
在闭包中也不是特别的。你也可以写 [weak x]
。 [...]
语法只是捕获列表。