Last active
November 7, 2017 19:11
-
-
Save ashtonmeuser/4df4bed49552aad2c0e91ec5f973579b to your computer and use it in GitHub Desktop.
Multicast delegate with +=, -= syntax, removes nil delegates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // MulticastDelegate.swift | |
| // | |
| // Created by Ashton Meuser on 2017-11-06. | |
| // Copyright © 2017 Ashton Meuser. All rights reserved. | |
| // | |
| // Delegate property: var multicastDelegate = MulticastDelegate<MyDelegateProtocol>() | |
| // Assign a delegate: multicastDelegate += self | |
| // Invoke delegate methods: multicastDelegate.invoke { $0.protocolMethod() } | |
| import Foundation | |
| public final class MulticastDelegate<T> { | |
| private var delegates = [Weak]() | |
| func add(_ delegate: T) { | |
| if Mirror(reflecting: delegate).subjectType is AnyClass { | |
| let weakValue = Weak(value: delegate as AnyObject) | |
| guard delegates.index(of: weakValue) == nil else { | |
| return | |
| } | |
| delegates.append(weakValue) | |
| } else { | |
| fatalError("Multicast delegates do not support value types") | |
| } | |
| } | |
| func remove(_ delegate: T) { | |
| if Mirror(reflecting: delegate).subjectType is AnyClass { | |
| let weakValue = Weak(value: delegate as AnyObject) | |
| guard let index = delegates.index(of: weakValue) else { | |
| return | |
| } | |
| delegates.remove(at: index) | |
| } | |
| } | |
| func invoke(_ invocation: (T) -> Void) { | |
| var indices = IndexSet() | |
| for (index, delegate) in delegates.enumerated() { | |
| if let delegate = delegate.value as? T { | |
| invocation(delegate) | |
| } else { | |
| indices.insert(index) | |
| } | |
| } | |
| self.removeObjects(atIndices: indices) | |
| } | |
| private func removeObjects(atIndices indices: IndexSet) { | |
| let indexArray = Array(indices).sorted(by: >) | |
| for index in indexArray { | |
| delegates.remove(at: index) | |
| } | |
| } | |
| } | |
| private final class Weak: Equatable { | |
| weak var value: AnyObject? | |
| init(value: AnyObject) { | |
| self.value = value | |
| } | |
| static func == (lhs: Weak, rhs: Weak) -> Bool { | |
| return lhs.value === rhs.value | |
| } | |
| } | |
| public func +=<T>(left: MulticastDelegate<T>, right: T) { | |
| left.add(right) | |
| } | |
| public func -=<T>(left: MulticastDelegate<T>, right: T) { | |
| left.remove(right) | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment