Swift,为什么不使用类方法需要关闭列表

时间:2018-05-08 22:34:14

标签: ios swift function methods strong-reference-cycle

如果函数基本上是闭包。为什么在关键字中引用self或其他实例属性时,类的方法不需要闭包列表。

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

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

    func otherFunc(){
        print()
    }
}

myFunc中是否存在参考周期?即,闭包指向self,实例指向函数。两者都不能解除分配。

2 个答案:

答案 0 :(得分:2)

闭包只能在闭合保持活动时引起参考循环。考虑一下:

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.closure强烈引用selfself强烈引用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的价值?我可能已经返回cx现在可能已超出范围。系统必须跟踪x(包括制作一个强引用,因此它不会解除分配),并通过捕获它或“关闭x”来提高保留循环的可能性。因此,在c中,x受到约束。它不是免费的。致电c()时,您无法通过。

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