Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save astrokin/56e1b462b8d73c4a01013b9508b069ea to your computer and use it in GitHub Desktop.
Save astrokin/56e1b462b8d73c4a01013b9508b069ea to your computer and use it in GitHub Desktop.
// https://github.com/avito-tech
private class ObserverBox<T>: Hashable {
typealias Observer = T
private(set) weak var disposable: AnyObject?
private let objectIdentifier: ObjectIdentifier
var observers = [Observer]()
let hashValue: Int
public init(disposable: AnyObject) {
self.disposable = disposable
objectIdentifier = ObjectIdentifier(disposable)
hashValue = objectIdentifier.hashValue
}
static func ==(left: ObserverBox, right: ObserverBox) -> Bool {
return left.objectIdentifier == right.objectIdentifier
}
}
public final class ObserverList<T> {
public typealias Observer = T
private var observers = Set<ObserverBox<Observer>>()
public var isEmpty: Bool {
return observers.isEmpty
}
public init() {}
public func addObserverIfNotContains(disposable: AnyObject, observer: Observer) {
let box = ObserverBox<Observer>(disposable: disposable)
guard !observers.contains(box) else { return }
addObserver(disposable: disposable, observer: observer)
}
// disposable can be any object.
// observer will be automatically removed after disposable will be disposed.
public func addObserver(disposable: AnyObject, observer: Observer) {
let box = ObserverBox<Observer>(disposable: disposable)
let (_, memberAfterInsert) = observers.insert(box)
memberAfterInsert.observers.append(observer)
}
public func removeObserver(disposable: AnyObject) {
observers.remove(ObserverBox<Observer>(disposable: disposable))
}
public func forEach(_ closure: (T) -> ()) {
let newObservers = observers.filter { box in
if box.disposable != nil {
box.observers.forEach(closure)
return true
} else {
return false
}
}
if newObservers.count != observers.count {
observers = Set(newObservers)
}
}
}
// Sample usage:
private struct MyObserver {
let onMyEvent: () -> ()
}
final class MyService {
private let observers = ObserverList<MyObserver>()
func add(observer object: AnyObject, onMyEvent: @escaping () -> ()) {
observers.addObserver(
disposable: object,
observer: MyObserver(onMyEvent: onMyEvent)
)
}
func someEvent() {
observers.forEach { $0.onMyEvent() }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment