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

问题描述 投票:0回答:2

我正在捕获一个委托引用,该引用最终设置为某个值,但最初为零。然而,即使设置了委托,捕获的引用仍然为零。

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
}

这是怎么回事?

swift closures automatic-ref-counting block
2个回答
3
投票

使用像

[weak delegate] in
这样的捕获列表将在闭包初始化时复制委托的值。因此,当委托在那一刻处于
nil
时,无论您稍后是否修改
nil
,if 都会留在闭包内
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
时是
closure


0
投票

上面的答案的解释不正确(由https://stackoverflow.com/users/1646335/andreas-oetjen)。当闭包捕获引用类型时,您引用它(您持有引用副本),这意味着如果

delegate
的属性发生更改,您将看到它的结果,无论持有
[delegate]
还是
[weak delegate]
(在第二种情况下,如果初始对象将被释放)。仅当
delegate
是值类型时,您才会有一份副本。 (将在编译时捕获,换句话说,它的第一个值)。上面的例子很令人困惑,因为对象本身(
delegate
)首先指向 nil,然后指向其他地址,但在闭包中,由于捕获列表,它保存的第一个地址为 nil。通过下面的示例查看(在 Playground 中运行):

class Delegate {
  var a: Int
  
  init(_ a: Int) {
    self.a = a
  }
}

class A {
  var delegate: Delegate?
  
  var closure: (() -> Void) = {}
  
  func bar() {
    print ("in bar ---------------------")
    delegate = Delegate(6)
    print ("delegate before: \(delegate)")
    closure = { [delegate] in print ("in closure: \(delegate?.a)")}
    closure()
    delegate?.a = 5
    print ("delegate after: \(delegate)")
    closure()
    delegate = Delegate(10)
    print ("delegate after: \(delegate)")
    closure()
  }
}

let a = A()
a.bar()
a.closure()
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.