Skip to content

Instantly share code, notes, and snippets.

@ashtonmeuser
Last active November 7, 2017 19:11
Show Gist options
  • Select an option

  • Save ashtonmeuser/4df4bed49552aad2c0e91ec5f973579b to your computer and use it in GitHub Desktop.

Select an option

Save ashtonmeuser/4df4bed49552aad2c0e91ec5f973579b to your computer and use it in GitHub Desktop.
Multicast delegate with +=, -= syntax, removes nil delegates
//
// 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