内存管理:具有弱var的保留周期,具有未拥有的非保留周期。为什么?

时间:2018-10-29 14:01:09

标签: ios swift memory-management retain-cycle

TL; DR

我有一个结构和一个类。该结构具有对该类实例的引用,而该对象具有捕获该结构的闭包。 如果对该对象的引用是 unowned ,则似乎它们都被取消了初始化。如果对该对象的引用是,则它们将彼此保留。 为什么?

我有一个结构和一个类,它们可以相互引用,我试图找出保留周期和打破周期的方法。所以我在操场上玩了一些。

给出以下代码:

    struct A {
    unowned var b: B

    init(b: B) {
        self.b = b
    }

    func setup() {
        print("A setup")

        b.didSomethingClosure = {
            print("A: b did do something")
            self.printSomething()
        }
    }

    func printSomething() {
        print("A: A did do something")
    }
}

class B {

    var didSomethingClosure:(() -> Void)?

    func doSomething() {
        print("B: do something")
        didDoSomething()
    }

    func didDoSomething() {
        print("B: did something")
        if let closure = didSomethingClosure {
            closure()
        }
    }

    deinit {
        print("B: deinit")
    }
}


do {

    let b = B()
    let a = A(b: b)

    a.setup()
    b.doSomething()

    print("end do")
}

如果结构中的var b声明为unowned var b: B,则释放B对象。如果我将代码修改为weak var b: B?,然后修改为b?.didSomethingClosure = ...,则将保留B对象。为什么?

1 个答案:

答案 0 :(得分:2)

我想问题是您在Playground中运行它。尝试在实际应用中运行它,您会发现B已释放

struct A {
    weak var b: B?

    init(b: B) {
        self.b = b
    }

    func setup() {
        print("A setup")

        b?.didSomethingClosure = {
            print("A: b did do something")
            self.printSomething()
        }
    }

    func printSomething() {
        print("A: A did do something")
    }
}

class B {

    var didSomethingClosure:(() -> Void)?

    func doSomething() {
        print("B: do something")
        didDoSomething()
    }

    func didDoSomething() {
        print("B: did something")
        if let closure = didSomethingClosure {
            closure()
        }
    }

    deinit {
        print("B: deinit")
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let b = B()
        let a = A(b: b)

        a.setup()
        b.doSomething()

        print("end do") // B is deallocated here
    }
}