Skip to content

Instantly share code, notes, and snippets.

@descorp
Created November 22, 2019 13:44
Show Gist options
  • Save descorp/c287a9bdf94b977754af5070e06280a2 to your computer and use it in GitHub Desktop.
Save descorp/c287a9bdf94b977754af5070e06280a2 to your computer and use it in GitHub Desktop.
Swift's C#-like events
import Foundation
public protocol Invocable: class {
func invoke(_ notification: String, _ data: Any)
}
public protocol Observer: Invocable {
associatedtype Value
typealias Callback = (_ notification: String, _ data: Value) -> Void
var callback: Callback { get }
}
class EventHandler<T>: Observer {
typealias Value = T
func invoke(_ notification: String, _ data: Any) {
if let data = data as? Value {
callback(notification, data)
}
}
let callback: Callback
init(callback: @escaping Callback) {
self.callback = callback
}
}
public protocol NotificationCenter {
func add<T: Observer>(observer: T, for notification: String)
func remove<T: Observer>(observer: T, for notification: String)
func post(notification: String, data: Any)
}
public final class NotificationCenterImpl: NotificationCenter {
typealias Storage = [String: [Invocable]]
private let queue = DispatchQueue(label: "NotificationCenter")
private var observers: Storage
init() {
observers = [:]
}
private var cuncurentObservers: Storage {
get {
var cuncurentObservers: Storage = [:]
queue.async { [unowned self] in cuncurentObservers = self.observers }
return cuncurentObservers
}
set(value) {
queue.async(flags: .barrier) {
self.observers = value
}
}
}
public func add<T: Observer>(observer: T, for notification: String) {
var array : [Invocable]
if let tempArray = cuncurentObservers[notification] {
array = tempArray
} else {
array = []
}
array.append(observer)
cuncurentObservers[notification] = array
}
public func remove<T: Observer>(observer: T, for notification: String) {
cuncurentObservers[notification]?.removeAll(where: { (item) -> Bool in item === observer })
}
public func post<T>(notification: String, data: T){
cuncurentObservers[notification]?.forEach( { item in
item.invoke(notification, data)
})
}
}
let observer1 = EventHandler<String>() { print($1) }
let observer2 = EventHandler<Float>() { print($1) }
let notificationCenter = NotificationCenterImpl()
notificationCenter.add(observer: observer1, for: "The Notification")
notificationCenter.add(observer: observer2, for: "The Notification")
notificationCenter.post(notification: "The Notification", data: "Stuff1")
notificationCenter.post(notification: "The Notification", data: Float(0.54))
notificationCenter.remove(observer: observer1, for: "The Notification")
notificationCenter.post(notification: "The Notification", data: "Stuff1")
notificationCenter.post(notification: "The Notification", data: Float(0.54))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment