Created
March 1, 2019 12:04
-
-
Save nkukushkin/0770dd46ba2fc713842111f8d65c1772 to your computer and use it in GitHub Desktop.
Barebones Observable
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
import Foundation | |
class ObservationToken: NSObject {} | |
class Observable<ValueType> { | |
private(set) var value: ValueType | |
func update(_ newValue: ValueType) { | |
let oldValue = value | |
value = newValue | |
for observation in observations.values { | |
observation(oldValue, newValue) | |
} | |
} | |
// MARK: - Observation | |
typealias Observation = (_ oldValue: ValueType, _ newValue: ValueType) -> Void | |
private var observations: [ObservationToken: Observation] = [:] | |
func observe(_ observation: @escaping Observation) -> ObservationToken { | |
let token = ObservationToken() | |
observations[token] = observation | |
return token | |
} | |
func stopObservation(for token: ObservationToken) { | |
observations[token] = nil | |
} | |
// MARK: - Initialization | |
init(initialValue: ValueType) { | |
self.value = initialValue | |
} | |
} | |
// MARK: - Scoped Observation | |
class ScopedObservationToken { | |
fileprivate let inner: ObservationToken | |
private let deinitHandler: (ObservationToken) -> Void | |
init(inner: ObservationToken, deinitHandler: @escaping (ObservationToken) -> Void) { | |
self.inner = inner | |
self.deinitHandler = deinitHandler | |
} | |
deinit { | |
deinitHandler(inner) | |
} | |
} | |
extension Observable { | |
func observe(_ observation: @escaping Observation) -> ScopedObservationToken { | |
let token: ObservationToken = observe(observation) | |
let scopedToken = ScopedObservationToken( | |
inner: token, | |
deinitHandler: { [weak self] token in | |
self?.stopObservation(for: token) | |
} | |
) | |
return scopedToken | |
} | |
func stopObservation(for token: ScopedObservationToken) { | |
stopObservation(for: token.inner) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment