【问题标题】:Optimizing capture lists优化捕获列表
【发布时间】:2018-06-06 03:55:27
【问题描述】:

有这种事吗?下面这两个有区别吗?一个比另一个更“正确”吗?

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

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

对

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

苹果在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()
}

【问题讨论】:

    标签: ios swift memory-management closures


    【解决方案1】:

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

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

    当闭包运行时,将在self 上查找当前 delegate。

    在 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,然后访问该弱引用 ({ self?.someProperty }) 上的属性,将获得在闭包执行时存在的属性值执行 .

    【讨论】:

    • 这很有意义,谢谢!那么,这应该是我的回答中行为的根本原因:lazy init 在声明闭包时触发,再加上它位于另一个线程而不是其他触发器的事实。
    【解决方案2】:

    [unowned objectOne = self.objectOne] 可能导致的问题之一是lazy var UIViews 和竞速条件:如果您不小心并且从不同线程调用lazy init,最终可能会创建两个实例。此外,如果您的superview.addSubview(objectOne) 调用在lazy init 中,则两个实例都将添加到superview,而objectOne 将指向两个实例之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      相关资源
      最近更新 更多