2017-07-09 61 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