Skip to content

Instantly share code, notes, and snippets.

@junpluse
Created March 10, 2019 09:18
Show Gist options
  • Save junpluse/4c5988e87ffe07501c25d0c6957befae to your computer and use it in GitHub Desktop.
Save junpluse/4c5988e87ffe07501c25d0c6957befae to your computer and use it in GitHub Desktop.
import Foundation
final class Subject<Value> {
let dispatchQueue: DispatchQueue
private static func makeDefaultDispatchQueue() -> DispatchQueue {
return DispatchQueue(label: String(reflecting: self), qos: .default, attributes: .concurrent)
}
private struct Observation {
let queue: DispatchQueue
let handler: (Value) -> Void
}
private var observations = [ObjectIdentifier: Observation]()
init(dispatchQueue: DispatchQueue = makeDefaultDispatchQueue()) {
self.dispatchQueue = dispatchQueue
}
}
extension Subject {
final class ObservationToken {}
func addObserver(on queue: DispatchQueue? = nil, handler: @escaping (Value) -> Void) -> ObservationToken {
let token = ObservationToken()
addObserver(token, on: queue) { _, event in
handler(event)
}
return token
}
func addObserver<T: AnyObject>(_ observer: T, on queue: DispatchQueue? = nil, handler: @escaping (T, Value) -> Void) {
let key = ObjectIdentifier(observer)
let observation = Observation(queue: queue ?? dispatchQueue) { [weak self, weak observer] value in
guard let observer = observer else {
self?.removeObservation(for: key)
return
}
handler(observer, value)
}
dispatchQueue.async(flags: .barrier) { [weak self] in
self?.observations[key] = observation
}
}
func removeObserver<T: AnyObject>(_ observer: T) {
let key = ObjectIdentifier(observer)
self.removeObservation(for: key)
}
private func removeObservation(for key: ObjectIdentifier) {
dispatchQueue.async(flags: .barrier) { [weak self] in
self?.observations[key] = nil
}
}
}
extension Subject {
func post(_ value: Value, group: DispatchGroup? = nil) {
dispatchQueue.async(group: group) {
for context in self.observations.values {
context.queue.async(group: group) {
context.handler(value)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment