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

Swift, why don't class methods need closure lists

提问人:webbyweb 提问时间:5/9/2018 更新时间:5/9/2018 访问量:800

问:

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

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

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

    func otherFunc(){
        print()
    }
}

myFunc 中不会有参考周期吗?即,闭包指向 self,实例指向函数。两者都不能被解除分配。

IOS Swift 函数 方法 strong-reference-cycle

评论


答:

3赞 zneak 5/9/2018 #1

仅当闭包保持活动状态时,闭包才可能导致参考周期。考虑一下:

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

闭包包含对 的引用,但一旦不再引用任何内容,该引用就会消失。例如:barfoobar

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

这不会创建引用循环,因为当返回时,闭包被销毁。同样,当您调用 and 时,您确实需要强引用 (编译器确保您拥有它),但由于您在函数末尾不再需要它,因此不会创建循环。fbarmyFuncotherFuncself

通常,闭包不会系统地创建参考循环,即使它是 。考虑以下情况:@escapingDispatch.async

class MyClass {
    func foo() {
        DispatchQueue.main.async {
            print(self)
        }
    }
}

实际上不会创建引用循环,因为即使闭包引用了一段时间,也不会引用闭包。selfself

危险的情况是这样的:

class MyClass {
    var closure: () -> ()

    func f() {
        self.closure = {
            print(self)
        }
    }
}

这个实际上创建了一个引用循环:对 有很强的引用,并且对 有很强的引用。self.closureselfselfself.closure

评论

1赞 Paulw11 5/9/2018
好答案;在 99% 的情况下,使用内联完成处理程序闭包,不需要整个“弱自我”舞蹈。引用的生存期是异步操作的生存期,其长度不足以引起问题。它最多会导致对象的释放延迟一小段时间。self
3赞 Rob Napier 5/9/2018 #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)是返回函数的函数。这里没有魔法。所有自由变量在调用期间提供。没有捕获任何内容。(您描述的“自由变量”是 ,但这不会改变任何事情。 没什么特别的,只是它周围有一点句法糖。selfself

这与闭包不同:

let c = { x.doThis() }
c()

当我打电话时,它怎么知道的值?我可能已经回来了,现在可能已经超出了范围。系统必须跟踪(包括进行强引用,以便它不会解除分配),并且它通过捕获它或“关闭 x”来做到这一点,这增加了保留循环的可能性。所以在 中,是绑定的。它不是免费的。调用时无法传递它。c()xcxxcxc()

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

评论

1赞 zneak 5/9/2018
IMO,将函数/方法视为不捕获任何变量的闭包的特例是公平的。Swift 将无捕获闭包推广到函数中:它特别允许你使用闭包表达式作为接受回调的 C 函数的参数。