代码之家  ›  专栏  ›  技术社区  ›  emenegro

在闭包中直接捕获值时的内存语义

  •  1
  • emenegro  · 技术社区  · 6 年前

    我最近在这篇文章中读到了 objc.io . 我认为这是一个很好的提示,我已经开始使用它了。

    虽然还没有完全澄清,但是我假设用这种方式捕获时没有保留周期,所以您会得到一个捕获的强引用,但是没有需要担心的保留周期。

    我意识到,甚至可以捕捉方法,而不仅仅是价值:

    .subscribe(onNext: { [showErrorAlert, populate] result in
        switch result {
        case .success(let book):
            populate(book)
        case .error(_):
            showErrorAlert(L10n.errorExecutingOperation.localized)
        }
    })
    

    我试图找到一些与这种捕获方式相关的文档,但是我找不到任何文档。这种做法安全吗?这和通常跳的舞一样吗 [weak self] , strongSelf = self 在封闭的内部?

    2 回复  |  直到 6 年前
        1
  •  1
  •   muvaaa    6 年前

    这种做法安全吗?这和平常跳舞一样吗 self],strongself=闭包内的self?

    是和否-对象的捕获方法也保留对象。捕获的方法可以访问实例中的任何内容,因此保留它是有意义的。

    另一方面,捕获一个属性 没有 保留实例。

    以下是一个简短的片段,您可以在操场上粘贴以供自己查看:

    import UIKit
    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    class A {
        let name: String
        init(name: String) {
            self.name = name
        }
    
        func a() {
            print("Hello from \(name)")
        }
    
        func scheduleCaptured() {
            print("Scheduling captured method")
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { [a] in
                a()
            }
        }
    
        func scheduleCapturedVariable() {
            print("Scheduling captured variable")
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { [name] in
                print("Hello from \(name)")
            }
        }
    
        deinit {
            print("\(name) deinit")
        }
    }
    
    var a1: A? = A(name: "instance 1")
    a1?.scheduleCapturedVariable()
    
    var a2: A? = A(name: "instance 2")
    a2?.scheduleCaptured()
    
    a1 = nil
    a2 = nil
    

    输出为:

    Scheduling captured variable
    Scheduling captured method
    instance 1 deinit
    Hello from instance 1
    Hello from instance 2
    instance 2 deinit
    

    你可以看到 instance 2 在被捕获的块被激发之前不会被取消初始化,而 instance 1 设置为零后立即脱初始化。

        2
  •  1
  •   Stimorol    6 年前
    1. 捕获实例方法是不安全的,除非您确定将在 deinit (F.E.你 绝对地 当然,它会触发有限的次数,然后序列总是结束)。对于非反应性用例也是如此。
    2. 该方法捕获力强(不能捕获力弱),因此闭包将保留引用,禁止ARC破坏它。因此 strongSelf 行为闭包只保留对对象的弱引用,在执行开始时将其绑定为强引用,然后在执行结束时释放强引用。