简体   繁体   中英

Swift retain cycle missing clarification

Apple has documentation that describes how retain cycles work in closures . This is their example of a closure that does not cause a retain cycle.

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

I occasionally like to pass a function definition into callback to try and rid my code of callback hell.

This example is a little contrived but does this cause a retain cycle? Would assigning a function like this to a closure ever cause a retain cycle?

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = self.returnHTML

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    func returnHTML() -> String {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

Your example isn't contrived enough, actually. Let's make it simpler:

class C {
    lazy var f: () -> () = {
        [unowned self] in
        print(self)
    }
    init() {}
    func doF() {
        self.f()
    }
    deinit {
        print("C is being deinitialized")
    }
}

Now let's test it:

    let c = C()
    c.doF()

Result: When c goes out of scope, we see "C is being deinitialized".

Okay, but now delete [unowned self] in . Now when we test it, we don't see "C is being deinitialized". We have a retain cycle.

So yes, you have self retaining a function that refers to self , that's a retain cycle. You are right to break the cycle with unowned self .

(Of course, in my example, I'm taking account of the way your lazy complicates the picture. If we don't say self.f() — that is, if we never ask the lazy var to initialize itself — then of course it doesn't matter what the initializer for f is: it never gets initialized so there can be no retain cycle. But that is an extremely improbable scenario; if you were never going to initialize the lazy var then you wouldn't have the lazy var to begin with.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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