我有与此类似的代码,与异步上下文中的事件处理有关:
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(code = exc_i386_bpt subcode = 0x0)
调试器显示self.b
完全正常:不是nil,所有值都是应该的。
但是,调试器还显示,同时主线程正在忙取消初始化相应的B
;它已在<... *>
暂停,即在foo
的引用可以从a
中删除之前。所以我觉得self.b
在这个时候会是一个不好的参考。
这似乎是不幸的时间 - 但我怎么能消除这种崩溃的可能性呢?毕竟,我不能阻止对bar()
的异步调用!
答案 0 :(得分:0)
基本上,我们在此处打破了unowned
的前提条件:即使调试器没有显示它,Foo.b
可以成为nil
Foo
的生命周期。当我们声称(通过使用unowned
)时,编译器认为我们不能这样做,所以我们崩溃了。
似乎有两种出路。
确保Foo.b
是包含对Foo
相应实例的强引用的最后一个对象。然后,应该删除两个对象&#34;一起&#34;,resp。在Foo.bar()
被取消初始化(或之后)时,无法调用Foo.b
。
使Foo.b
成为弱引用,即将其声明为weak var b: B?
。这使得代码更加混乱,但至少它可以变得安全。