简体   繁体   English

self 何时保留闭包?

[英]When does a self retain a closure?

我一直在阅读内存管理一段时间,我知道当闭包保留 self 和 self 保留闭包时,我们应该放 [weak self] 来打破循环,我的问题是闭包什么时候保留 self 什么时候 self 保留一个关闭?

It's usually pretty obvious, though not always.通常很明显,但并非总是如此。

  • The closure retains thing if it mentions thing or any property of thing .封闭保留thing ,如果它提到thing或任何财产thing

  • thing retains the closure if it has a property that is or contains a function and that function is the closure.如果thing具有属于或包含函数的属性并且该函数是闭包,则它保留闭包。

The artificial example I use in my book is:我在书中使用的人工示例是:

class FunctionHolder {
    var function : (() -> ())?
}
func testFunctionHolder() {
    let fh = FunctionHolder()
    fh.function = {
        print(fh)
    }
}

Here, thing is fh , a FunctionHolder instance.这里的thingfh ,一个 FunctionHolder 实例。 We assign to the function property of fh a closure that mentions fh .我们为fhfunction属性分配一个提到fh的闭包。 That's a retain cycle.这是一个保留周期。

The problem in real life is that this happens without your realizing it.现实生活中的问题是,这会在你没有意识到的情况下发生。 You know you're retaining something , but you might not realize that the something is or contains a closure.您知道您正在保留某物,但您可能没有意识到某物是或包含一个闭包。 The classic example is when you call经典的例子是当你打电话

let ob = NotificationCenter.default.addObserver(forName:...

That call returns an observer object, which you retain so that you will get notifications.该调用返回一个观察者对象,您保留该对象以便获得通知。 But you also hand that call a closure, and if it mentions you, you've got a retain cycle, because you are retaining the observer which contains the closure which mentions you.但是你也传递了一个闭包,如果它提到你,你就有了一个保留周期,因为你保留了包含提到你的闭包的观察者。

And there are a number of other common pitfall situations of that sort.还有许多其他类似的常见陷阱情况。

Here is an example:下面是一个例子:

class ViewController: UIViewController {

    var data = Data() {
        didSet {
            // do something
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        Service.loadData { data in
            self.data = data
        }
        perform(#selector(tryToDismiss), with: self, afterDelay: 0.5)
    }

    @objc func tryToDismiss() {
        dismiss(animated: true)
    }

    deinit {
        print("ViewController got deinit")
    }
}

class Service {

    static func loadData(completion: @escaping (Data) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            completion(Data())
        }
    }
}

You can see that even though the view controller is getting dismissed after 0.5 seconds of getting loaded it's not getting deinitialized because of the closure that completes the load data after 1 second.您可以看到,即使视图控制器在加载 0.5 秒后被解散,它也不会被取消初始化,因为关闭在 1 秒后完成加载数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM