优化捕获列表

时间:2017-12-24 09:12:14

标签: ios swift memory-management closures

有这样的事吗?下面两个有什么区别吗?比另一个更“正确”吗?

所有对象都是self的属性(比如一个视图控制器),其生命周期与self相同。我们可以引入一个寿命比self更短的对象,weak,但同样的问题适用。

objectOne.doSomething { [unowned self] in
    self.objectTwo.finish()
    self.tableView.reloadData()
    // self.someDelegate?.didFinishSomething()
}

VS

objectOne.doSomething { 
    [unowned objectTwo = self.objectTwo,
    unowned tableView = self.tableView
    // weak someDelegate = self.delegate
    ] in
    objectTwo.finish()
    tableView.reloadData()
    // someDelegate?.didFinishSomething()
}

Apple在their docs中有这个例子:

lazy var someClosure: () -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here

    delegate?.doSomething()
}

在这种情况下,delegate的生命周期可能比self短,但为什么不这样使用呢?

lazy var someClosure: () -> String = { 
    [unowned self] in
    // closure body goes here

    self.delegate?.doSomething()
}

2 个答案:

答案 0 :(得分:1)

是的,有一个重要的区别。对于Apple文档,您提供了代码替代方案:

lazy var someClosure: () -> String = { 
    [unowned self] in
    // closure body goes here

    self.delegate?.doSomething()
}
当闭包运行时,

将在delegate上查找当前 self

在Apple示例版本中:

lazy var someClosure: () -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here

    delegate?.doSomething()
}

捕获列表中的弱delegate var是复制关闭声明时存在的delegate上的self指针,而不是执行。因此,如果self.delegate的值在声明闭包后发生变化,并且在闭包运行时不同,那么闭包的Apple版本将具有一个nil委托(假设因为对旧委托的引用很弱)并且什么都不做。

因此,作为一般规则,在捕获列表([someIdentifier = someProperty])中复制值或引用是如何使用在定义闭包时存在的值或引用。虽然在捕获列表([weak self])中声明弱或无主,然后访问该弱引用({ self?.someProperty })上的属性,但在闭包执行时将获得属性的值

答案 1 :(得分:0)

[unowned objectOne = self.objectOne]可能导致的一个问题是lazy var UIViews和竞争条件:如果你不小心,lazy init从不同的线程调用,两个实例可能最终被创造出来。此外,如果您的superview.addSubview(objectOne)调用位于lazy初始化版中,则两个实例都将添加到superviewobjectOne将指向这两个实例中的一个。