2017-07-09 63 views
1

考慮下面的代碼:傳遞實例方法回調類初始化

class Bar { 
    let callback:() ->() 

    init(callback: @escaping() ->()) { 
     self.callback = callback 
    } 

    func event() { 
     self.callback() 
    } 
} 

class Foo { 
    let bar: Bar 

    init() { 
     self.bar = Bar(callback: self.handler) 
    } 

    func handler() { 
     print("Handled") 
    } 
} 

的基本想法是,我們希望每個FooBar,其中,當event()上調用Foobar,將調用Foo的處理程序方法。但是,上述設置警告在Foo的初始化之前,因爲我們在所有實例屬性初始化之前使用了self

我明白爲什麼這是一個錯誤:編譯器不能保證該方法傳遞給Bar小號初始化完成的初始化不會被前Foo莫名其妙地稱爲'(例如Bar可致電callback PARAM就在它的初始值設定項或另一個線程可能會在Bar的初始化程序返回之後但正好在結果分配給Foobar)之後調用event()

我的問題是,是否有一種方法來實現這種模式,我失蹤了?一個解決辦法是讓bar的IUO var並將其分配給nil只是打電話之前Barinit --as只要我們知道回調也不會在不適當的時候被調用(或者只要我們不使用barhandler)應該沒有問題。但是,這對我來說很不好,我很樂意聽到替代品,如果它們存在。

回答

4

這裏的另一種選擇:

class Foo { 
    let bar: Bar 

    init() { 
     self.bar = Bar(callback: self.handler) 
    } 

    let handler:() -> Void = { 
     print("handled") 
    } 
} 

也許它並不感到相當爲哈克,但如果handler涉及self可言,這是不行的。你也不能用委託來做。

是啊,據我所知,要做到這一點的唯一方法是使bar隱式展開var

class Foo { 
    var bar: Bar! 

    init() { 
     bar = Bar(callback: handler) 
    } 

    func handler() { 
     print("Handled") 
    } 
} 
+0

這實際上不是一個壞的解決方案,看起來乾淨了一點。另一種解決方案是在Bar上有'listenForEvents(callback:)'方法,並且回調是可選的(或IUO)。 – Jumhyn