0

我有类似的代码,与异步上下文中的事件处理有关:

class A {
    var foos: Set<Fooable>
}

protocol Fooable {
    func bar()
}

class B {
    var a: A
    var foo: Foo!

    init(a: A) {
        self.a = a
    }

    func start() {
        self.foo = Foo(self)
        self.a.foos.insert(self.foo)
    }

    deinit {
        <... *>
        if self.foo != nil {
            self.a.remove(self.foo)
        }
    }


    class Foo: Fooable {
        unowned let b: B

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

        func bar() { <... #> }
    }
}

我认为这应该是安全的代码:在一个实例b消失之前,它会清除对其的所有引用foo,因此引用Foo.b永远不会成为问题。

self.b但是,我从内部的访问中得到这个错误Foo.bar()(在一些 GCD 队列上运行,而不是在主队列上运行):

exc_breakpoint(代码=exc_i386_bpt 子代码=0x0)

调试器显示这self.b完全没问题:不是零,所有值都是应有的。

但是,调试器也显示,与此同时,主线程正忙于去初始化相应的B; 它在 中暂停<... *>,即在foo可以从 中删除对 的引用之前aself.b所以对我来说,在这个时候这将是一个不好的参考是有道理的。

这似乎是一个不幸的时机——但我怎样才能消除这种崩溃的可能性呢?bar()毕竟,我无法阻止异步调用的发生!

4

1 回答 1

0

基本上,我们打破了unowned这里的先决条件:即使调试器没有显示它,Foo.b 可以nilFoo. 当我们声称(通过使用unowned)它不能时,编译器相信我们,所以我们崩溃了。

似乎有两条出路。

  1. 确保这Foo.b是最后一个对Foo. 然后,这两个对象应该“一起”被删除,分别。在被取消初始化(或之后)时,Foo.bar()不可能发生调用。Foo.b

  2. Foo.b一个弱引用,即将它声明为weak var b: B?. 这使代码更加混乱,但至少可以使其安全。

于 2017-07-24T15:01:17.997 回答