8

Swift でマルチキャスト デリゲート機能を実装しようとしています。Objective 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()」をノード内のすべてのデリゲートに与えるため。誰でもこれで私を助けることができますか?

4

6 に答える 6

9

スウィフト 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.

このブログ投稿に基づいています。

于 2016-11-10T23:33:33.203 に答える
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()
    }
  }
}
于 2015-05-10T13:02:09.680 に答える
2

これは、Swift 2.0 プロトコル拡張を使用したマルチキャスト デリゲートの実装です。また、代理人を削除する機能を追加しました。そうするために、デリゲート型を NSObjectProtocol に準拠させましたが、削除に === 演算子を使用する参照型であることを宣言する方法がわかりませんでした。

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() }
    }
}
于 2015-10-23T11:13:38.540 に答える
1

GitHub に Swift マルチキャスト デリゲートの実装を追加しました: https://github.com/tumtumtum/SwiftMulticastDelegate

基本的に、オーバーロードされた演算子「=>」をブロックで使用して呼び出しを実行します。内部的に、MulticastDelegate はすべてのリスナーに対してそのブロックを呼び出します。

class Button
{
  var delegate: MulticastDelegate<ButtonDelegate>?

  func onClick()
  {
    self.delegate => { $0.clicked(self) }
  }  
}
于 2016-05-25T10:07:49.357 に答える
0

追加できる場合があります

@objc

もちろん、プロトコルとクラスに対しては、純粋な迅速な処理を行うことはもうありません...しかし、動的ディスパッチ機能が再度有効になるため、問題が解決する可能性があります。

于 2015-03-26T12:09:29.137 に答える