内存管理:使用弱引用避免保留周期,使用无主引用避免非保留周期。为什么?

4

TL;DR

我有一个结构体和一个类。该结构体引用了该类的实例,而该对象具有捕获该结构体的闭包。 如果对该对象的引用是unowned,那么它们两者都会被析构。如果对该对象的引用是weak,则它们会互相保留。 为什么?

我有一个结构体和一个类,它们可能相互引用,我试图理解保留周期以及打破它们的方法。所以我在playground中做了一些尝试。

给出以下代码:

    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")
}

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

未拥有的变量?那甚至无法编译... - J. Doe
为什么它不能编译? - bursyllac
1个回答

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
    }
}

哇,这没在我脑海中闪过。它也没有任何意义。有解释还是只是一个错误? - bursyllac
1
@bursyllac 看起来像是一个 playground 的 bug。我稍微测试了一下你的代码,这个问题并不是与闭包和内存管理有关的。 - Taras Chernyshenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接