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 中的闭包被破坏。类似地,当您调用 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有强引用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][...] 语法只是捕获列表。