Swift 异步函数调用与无主对象的去初始化冲突

Swift 异步函数调用与无主对象的去初始化冲突,swift,concurrency,automatic-ref-counting,deinit,Swift,Concurrency,Automatic Ref Counting,Deinit,我有类似的代码,与异步上下文中的事件处理相关: 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) se

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

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() { <... #> }
    }
}
A类{
var-foos:Set
}
协议可食{
func bar()
}
B类{
变量a:a
福娃:福娃!
初始(a:a){
self.a=a
}
func start(){
self.foo=foo(self)
self.a.foos.insert(self.foo)
}
脱硝{
如果self.foo!=nil{
self.a.remove(self.foo)
}
}
Foo类:可食{
无主出租
初始化(b:b){
self.b=b
}
func bar(){}
}
}
我认为这应该是安全的代码:在
b
的实例消失之前,它会清除对其
foo
的所有引用,因此引用
foo.b
应该永远不会成为问题

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

exc_断点(代码=exc_i386_bpt子代码=0x0)

调试器显示,
self.b
是完全正确的:不是零,所有值都是应该的

但是,调试器还显示,与此同时,主线程正忙于取消初始化相应的
B
;它在
中暂停,即在
a
中删除对
foo
的引用之前。因此,对我来说,
self.b
在这个时候将是一个不好的参考


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

基本上,我们在这里打破了
无主
的先决条件:即使调试器没有显示它,
Foo.b
Foo
的生命周期内也可以变成
nil
。当我们声称(使用
无主
)它不能时,编译器相信了我们,所以我们崩溃了

似乎有两条出路

  • 确保
    Foo.b
    是保存对
    Foo
    的各个实例的强引用的最后一个对象。然后,两个物体应分别“一起”移除。当
    Foo.b
    被取消初始化时(或之后),不可能调用
    Foo.bar()

  • 使
    Foo.b
    成为弱引用,即将其声明为
    弱变量b:b?
    。这使得代码更加混乱,但至少可以保证安全