带有零值的Swift闭包捕获列表

时间:2018-10-18 07:02:08

标签: swift closures automatic-ref-counting block

我正在捕获一个委托引用,该引用最终设置为某个值,但最初为nil。但是,即使设置了委托,捕获的引用也将保持为零。

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak delegate] in
    delegate?.something() // delegate is nil
}

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in
    self?.delegate?.something() // delegate is not nil
}

这是怎么回事?

1 个答案:

答案 0 :(得分:1)

使用[weak delegate] in之类的列表,将在初始化关闭的那一刻复制代表的值。因此,当委托在那一刻是nil时,如果将nil留在闭包中,则不管以后是否修改self.delegate[weak self]也是如此,除了self通常不会在Swift中更改之外,几乎没有例外。

检查此示例:

class Delegate {

}

class A {
    var delegate:Delegate?

    func foo() {
        print ("in foo ---------------------")
        delegate = nil
        print ("delegate before: \(delegate)")  // prints: "nil"
        var closure = { print ("in closure: \(self.delegate)")}
        closure()   // prints: "in closure: nil"
        delegate = Delegate()
        print ("delegate after: \(delegate)") // prints "Optional(SwiftPlayground.Delegate)"
        closure() // prints "in closure: Optional(SwiftPlayground.Delegate)"
    }
    func bar() {
        print ("in bar ---------------------")
        delegate = nil  // prints "nil"
        print ("delegate before: \(delegate)")
        var closure = { [weak delegate] in print ("in closure: \(delegate)")}
        closure() // prints: "in closure: nil"
        delegate = Delegate()   // prints "Optional(SwiftPlayground.Delegate)"
        print ("delegate after: \(delegate)")
        closure() // prints "nil"
    }
}

let a = A()
a.foo()
a.bar()

这里,closure()中的最后一个func bar调用将打印nil,因为delegate当时是nil初始化。