我想在事情发生变化时使用多播委托通知多个对象。我读过的教程解释了这个,有一个协议,只有一个函数直接在代理数组上调用。当只定义了一个函数时,它工作正常。我的协议有6个功能。我想避免创建6个单独的函数,并重用一个可以应用于我的代理数组的函数。
简单的例子:(我知道这不起作用,但我只是想了解我的想法。
protocol MyProtocol {
func method1()
func method2()
func method3()
}
class TestClass {
var delegates = [MyProtocol]()
func invokeDelegates(delegateMethod: () -> ()) {
for delegate in delegates {
delegate.delegateMethod()
}
}
}
显而易见的问题是编译器抱怨原始协议中没有定义“delegateMethod”。有没有办法将该方法转换为MyProtocol的一部分,编译器会信任我吗?
这甚至可能吗?
答案 0 :(得分:18)
以下是我在项目中使用的多播委托模式的要点。它还可以防止强大的参考周期(内存泄漏)。 WeakWrapper处理这个问题。
确定。在一些解决方案中,我看到了错误(强大的保留周期,竞争条件......)
以下是基于1天研究的结果。对于代理堆栈,我使用了NSHashTable,因此所有代理都有弱引用。
class MulticastDelegate <T> {
private let delegates: NSHashTable<AnyObject> = NSHashTable.weakObjects()
func add(delegate: T) {
delegates.add(delegate as AnyObject)
}
func remove(delegate: T) {
for oneDelegate in delegates.allObjects.reversed() {
if oneDelegate === delegate as AnyObject {
delegates.remove(oneDelegate)
}
}
}
func invoke(invocation: (T) -> ()) {
for delegate in delegates.allObjects.reversed() {
invocation(delegate as! T)
}
}
}
func += <T: AnyObject> (left: MulticastDelegate<T>, right: T) {
left.add(delegate: right)
}
func -= <T: AnyObject> (left: MulticastDelegate<T>, right: T) {
left.remove(delegate: right)
}
如何设置委托:
object.delegates.add(delegate: self)
如何在代理上执行功能:
而不是
delegate?.delegateFunction
你使用
delegates.invoke(invocation: { $0.delegateFunction })
答案 1 :(得分:7)
您需要更改invokeDelegates
的签名以获取类型(MyProtocol) -> ()
的闭包,然后您需要将每个委托传递给闭包。
protocol MyProtocol {
func method1()
func method2()
func method3()
}
class TestClass {
var delegates = [MyProtocol]()
func invokeDelegates(delegateMethod: (MyProtocol) -> ()) {
for delegate in delegates {
delegateMethod(delegate)
}
}
}
闭包应该只在其参数上调用适当的委托方法。 Swift可以推断出闭包的参数和返回类型,你可以使用简写$0
来引用参数,所以闭包可以很短:
let tester = TestClass()
tester.invokeDelegates(delegateMethod: { $0.method1() })
另一方面,您可以直接在Collection.forEach
数组上使用delegates
(如果可以访问)并跳过invokeDelegates
方法:
tester.delegates.forEach { $0.method1() }