2017-07-24 40 views
0

我有類似下面的代碼,涉及事件的異步內容處理:的b實例前:異步函數調用衝突

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() { <... #> } 
    } 
} 

我想,這應該是安全的代碼已經不存在了,它會清除對foo的所有引用,因此引用Foo.b不應該是一個問題。

不過,我從Foo.bar()內的self.b訪問出現此錯誤(在某些GCD隊列運行,而不是主):

exc_breakpoint(代碼= exc_i386_bpt子碼=爲0x0)

調試器顯示self.b是完全正確的:不是零,所有的值都是它們應該是的。

但是,調試器還顯示,同時主線程正在忙於去初始化對應的B;它在<... *>中暫停,即在參考foo之前可以從a中刪除。所以對我來說self.b在這個時候是一個不好的參考。

這似乎是不幸的時機 - 但我該如何消除這個崩潰的潛力?畢竟,我無法阻止異步調用bar()

回答

0

基本上,我們打破了unowned這裏的前提條件:即使調試器不顯示它,Foo.b可以一個Foo的生命週期中成爲nil。編譯器相信我們,當我們聲稱(通過使用unowned)它不能,所以我們崩潰。

似乎有兩種方法。

  1. 確保Foo.b是保持強引用的Foo各自的情況下的最後一個對象。然後,這兩個物體應該「一起」去除,在Foo.b正在被初始化(或之後)時,不可能發生對Foo.bar()的調用。

  2. 使Foo.b成爲弱引用,即聲明它爲weak var b: B?。這會使代碼更加混亂,但至少可以使其安全。