Strong, weak references + Mirror: causing leak

Viewed 136

The Parent class below has strong & weak references to a single child object. The child object is never freed. Remove the weak reference and the child is freed.

Calling the Mirror method is required to make this leak, but I cannot understand why using a Mirror would cause this behavior. The results of the Mirror are not retained.

With both weak & strong refs, only the parent deinit is executed!

Parent deinit

I expect to see both parent & child objects freed, so that the log says:

Parent deinit
DeinitLogger deinit

Remove the weak reference and the log shows both objects deinit, as expected.

Can you help me understand why this is leaking? (This is not a playground, but in an app).

class DeinitLogger {
    deinit {
        print("DeinitLogger \(#function)")
    }
}

class Parent: NSObject {

    weak var weakLogger: DeinitLogger?
    var strongLogger: DeinitLogger

    override init() {

        let logger = DeinitLogger()

        // Create a weak ref
        weakLogger = logger  // comment out this line, no leak!

        // Create a strong ref to same object.
        strongLogger = logger

        super.init()

        // Invoking mirror and adding the properties to a dict leaks when one of the
        // properties is weak.
        let dict = dictionaryOfProps()
        print(dict)
    }

    deinit {
        print("Parent \(#function)")
    }

    /// Generates a dictionary of property names -> properties
    /// e.g. "strongLogger" -> type of strongLogger.
    private func dictionaryOfProps() -> [String: Any] {
        var result = [String: Any]()
        let mirror = Mirror(reflecting: self)
        for case let(label?, value) in mirror.children {
            result[label] = value
        }
        return result
    }
}

// Chuck these two lines in a viewDidLoad(), or anywhere. 
var o: Parent? = Parent()
o = nil // everything should be freed here.
1 Answers
Related