Swift语言多播委托
我想在Swift中实现多播委托function。 在Objective C中,我们有这个优秀的实现
https://github.com/robbiehanson/XMPPFramework/blob/master/Utilities/GCDMulticastDelegate.m
我刚刚创build了这个基本function:
protocol MyProtocol : class{ func testString()-> String; } class MulticastDelegateNode <T:AnyObject> { weak var delegate : T? init(object : T){ self.delegate = object; } } class MulticastDelegate <T:AnyObject> { var delegates = Array<MulticastDelegateNode<T>>() func addDelegate(delegate : T){ var newNode = MulticastDelegateNode(object : delegate); delegates.append(newNode); } func removeDelegate(delegate : AnyObject){ self.delegates = self.delegates.filter({ (node : MulticastDelegateNode) -> Bool in return node.delegate !== delegate; }); } } class OP { var delegate = MulticastDelegate<MyProtocol>(); func process(){ //... //make actions //notify the objects! } }
我的问题是,似乎我无法想出一个办法来做到这一点:
delegate.testString()
为了给命令'testString()'给节点中的所有委托。 谁能帮我这个?
Swift 3的实现:
class MulticastDelegate<T> { private var delegates = [Weak]() func add(_ delegate: T) { if Mirror(reflecting: delegate).subjectType is AnyClass { delegates.append(Weak(value: delegate as AnyObject)) } else { fatalError("MulticastDelegate does not support value types") } } func remove(_ delegate: T) { if type(of: delegate).self is AnyClass { delegates.remove(Weak(value: delegate as AnyObject)) } } func invoke(_ invocation: (T) -> ()) { for (index, delegate) in delegates.enumerated() { if let delegate = delegate.value { invocation(delegate as! T) } else { delegates.remove(at: index) } } } } private class Weak: Equatable { weak var value: AnyObject? init(value: AnyObject) { self.value = value } } private func ==(lhs: Weak, rhs: Weak) -> Bool { return lhs.value === rhs.value } extension RangeReplaceableCollection where Iterator.Element : Equatable { @discardableResult mutating func remove(_ element : Iterator.Element) -> Iterator.Element? { if let index = self.index(of: element) { return self.remove(at: index) } return nil } }
你可以用下面的方法testing它
protocol SomeDelegate: class { func onSomeEvent() } class SomeDelegateImpl: SomeDelegate { let value: Int init(value: Int) { self.value = value } func onSomeEvent() { print("Invoking delegate \(value)") } } let multicastDelegate = MulticastDelegate<SomeDelegate>() func testInvoke() { multicastDelegate.invoke { $0.onSomeEvent() } } print("Adding first delegate.") let delegate1 = SomeDelegateImpl(value: 1) multicastDelegate.add(delegate1) testInvoke() let delegate2 = SomeDelegateImpl(value: 2) print("Adding second delegate.") multicastDelegate.add(delegate2) testInvoke() print("Removing first delegate.") multicastDelegate.remove(delegate1) testInvoke() print("Adding third delegate.") ({ let delegate3 = SomeDelegateImpl(value: 3) multicastDelegate.add(delegate3) testInvoke() })() print("Third delegate is deallocated by ARC.") testInvoke()
它打印:
Adding first delegate. Invoking delegate 1. Adding second delegate. Invoking delegate 1. Invoking delegate 2. Removing first delegate. Invoking delegate 2. Adding third delegate. Invoking delegate 2. Invoking delegate 3. Third delegate is deallocated by ARC. Invoking delegate 2.
基于这个博客文章 。
一个关于MulticastDelegate的简单演示。
class DelegateMulticast <T> { private var delegates = [T]() func addDelegate(delegate: T) { delegates.append(delegate) } func invokeDelegates(invocation: (T) -> ()) { for delegate in delegates { invocation(delegate) } } } protocol MyProtocol { func testString() -> String } class OP { var delegates = DelegateMulticast<MyProtocol>() func process(){ delegates.invokeDelegates{ $0.testString() } } }
这里是我使用Swift 2.0协议扩展实现多播委托。 另外我已经添加删除代表的能力。 要做到这一点,我已经使我的委托types符合NSObjectProtocol,没有得到如何声明它应该是引用types使用===运算符为删除。
protocol MulticastDelegateContainer { typealias DelegateType : NSObjectProtocol var multicastDelegate : [DelegateType] {set get} } extension MulticastDelegateContainer { mutating func addDelegate(delegate : DelegateType) { multicastDelegate.append(delegate) } mutating func removeDelegate(delegate : DelegateType) { guard let indexToRemove = self.multicastDelegate.indexOf({(item : DelegateType) -> Bool in return item === delegate }) else {return} multicastDelegate.removeAtIndex(indexToRemove) } func invokeDelegate(invocation: (DelegateType) -> ()) { for delegate in multicastDelegate { invocation(delegate) } } }
这里是使用的例子
@objc protocol MyProtocol : NSObjectProtocol { func method() } class MyClass : MulticastDelegateContainer { typealias DelegateType = MyProtocol var multicastDelegate = [MyProtocol]() func testDelegates() { invokeDelegate { $0.method() } } }
我在GitHub上添加了一个Swift多播委托的实现: https : //github.com/tumtumtum/SwiftMulticastDelegate
基本上你使用重载的运算符“=>”来执行调用。 MulticastDelegate内部将为每个监听者调用该块。
class Button { var delegate: MulticastDelegate<ButtonDelegate>? func onClick() { self.delegate => { $0.clicked(self) } } }
好。 在一些解决scheme中,我看到了错误(强大的保留周期,竞争条件…)
这是我结合1天的研究。 对于我使用NSHashTable的委托堆栈,所有代表都有弱引用。
Swift 3.1
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 })
您可能可以添加
@objc
对于你的协议和类,当然,那么你不再是纯粹的快速…但这可能会解决您的问题,因为它将重新启用dynamic调度权力。