Last active
June 5, 2018 05:15
-
-
Save mansbernhardt/724e9a11e6f58a0ff1f279b0afb62d95 to your computer and use it in GitHub Desktop.
API Design - Deriving Signal Playground
This file contains 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
//: Playground - noun: a place where people can play | |
import Foundation | |
protocol Disposable { | |
func dispose() | |
} | |
final class Disposer: Disposable { | |
private var disposer: (() -> Void)? | |
init(_ disposer: @escaping () -> Void) { | |
self.disposer = disposer | |
} | |
func dispose() { | |
disposer?() | |
disposer = nil // Stop from being called more than once | |
} | |
deinit { dispose() } | |
} | |
final class DisposeBag: Disposable { | |
fileprivate var disposables: [Disposable] = [] | |
func dispose() { | |
disposables.forEach { $0.dispose() } | |
disposables = [] | |
} | |
deinit { dispose() } | |
} | |
func +=(bag: DisposeBag, disposable: Disposable) { | |
bag.disposables.append(disposable) | |
} | |
typealias Key = UInt64 | |
private var _nextKey: Key = 0 | |
func generateKey() -> Key { | |
_nextKey = _nextKey &+ 1 | |
return _nextKey | |
} | |
final class Callbacker<Value> { | |
private var callbacks: [Key : (Value) -> ()] = [:] | |
func addCallback(_ callback: @escaping (Value) -> Void) -> Disposable { | |
let key = generateKey() | |
callbacks[key] = callback | |
return Disposer { | |
self.callbacks[key] = nil | |
} | |
} | |
public func callAll(_ value: Value) { | |
callbacks.forEach { $1(value) } | |
} | |
} | |
final class Signal<Value> { | |
let onValue: (@escaping (Value) -> ()) -> Disposable | |
init(onValue: @escaping (@escaping (Value) -> ()) -> Disposable) { | |
self.onValue = onValue | |
} | |
} | |
extension Signal { | |
func map<T>(transform: @escaping (Value) -> T) -> Signal<T> { | |
return Signal<T> { callback in | |
self.onValue { event in | |
callback(transform(event)) | |
} | |
} | |
} | |
} | |
let bag = DisposeBag() | |
let passwordCallbacker = Callbacker<String>() | |
let passwordSignal = Signal(onValue: passwordCallbacker.addCallback) | |
let enableButtonSignal = passwordSignal.map { $0.count > 5 } | |
bag += enableButtonSignal.onValue { | |
print("Button enabled", $0) | |
} | |
passwordCallbacker.callAll("") | |
passwordCallbacker.callAll("1234") | |
passwordCallbacker.callAll("123456") | |
extension NotificationCenter { | |
func signal(forName name: Notification.Name?, object: Any? = nil) -> Signal<Notification> { | |
return Signal { completion in | |
let observer = self.addObserver(forName: name, object: object, queue: nil, using: completion) | |
return Disposer { | |
self.removeObserver(observer) | |
} | |
} | |
} | |
} | |
extension Notification.Name { | |
static let somethingHappend = Notification.Name(rawValue: "somethingHappend") | |
} | |
bag += NotificationCenter.default.signal(forName: .somethingHappend).onValue { _ in | |
print("Notification somethingHappend") | |
} | |
NotificationCenter.default.post(name: .somethingHappend, object: nil) | |
print("Got here") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment