Swift语言多播代表

时间:2014-11-16 15:28:30

标签: ios cocoa swift multicastdelegate

我正在尝试在Swift中实现多播委托功能。在目标C中,我们有这个出色的实现

https://github.com/robbiehanson/XMPPFramework/blob/master/Utilities/GCDMulticastDelegate.m

我刚刚创建了这个基本功能:

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()'提供节点中的所有委托。任何人都可以帮我这个吗?

6 个答案:

答案 0 :(得分:8)

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
    }
}

您可以使用以下方法进行测试:

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.

基于this blog post

答案 1 :(得分:3)

关于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()
    }
  }
}

答案 2 :(得分:2)

这是我使用Swift 2.0协议扩展实现的多播委托。此外,我还添加了删除代表的功能。为此,我已经使我的委托类型符合NSObjectProtocol,没有得到如何声明它应该是引用类型使用===运算符来删除。

while (n > 0 AND MOD(count, 2) = 0)

以下是使用示例

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)
        }
    }
}

答案 3 :(得分:2)

确定。在一些解决方案中,我看到了错误(强大的保留周期,竞争条件......)

以下是基于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 })

答案 4 :(得分:1)

我在GitHub上添加了Swift多播委托的实现:https://github.com/tumtumtum/SwiftMulticastDelegate

基本上你使用重载运算符&#34; =&gt;&#34;用块来执行调用。在内部,MulticastDelegate将为每个侦听器调用该块。

class Button
{
  var delegate: MulticastDelegate<ButtonDelegate>?

  func onClick()
  {
    self.delegate => { $0.clicked(self) }
  }  
}

答案 5 :(得分:0)

您可以添加

@objc

到您的协议&amp;这些课程,当然你不再是纯粹的快速...但这可能会解决你的问题,因为它将重新启用动态调度权力。