Skip to content

Instantly share code, notes, and snippets.

@andersio
Created May 26, 2016 09:15
Show Gist options
  • Save andersio/52b323cf9b720148fa269dbde96371d6 to your computer and use it in GitHub Desktop.
Save andersio/52b323cf9b720148fa269dbde96371d6 to your computer and use it in GitHub Desktop.
AnyPropertyRelay
/// A relay of `AnyProperty`, enforcing the consistent order of `value` and signal
/// events.
final private class AnyPropertyRelay<Value> {
let atomicBox: Atomic<Value?>
let disposable: CompositeDisposable
let (relaySignal, relayObserver) = Signal<Value, NoError>.pipe()
var value: Value {
return atomicBox.value!
}
/// A producer which creates signals retaining the relay until the disposal of
/// the signal.
var producer: SignalProducer<Value, NoError> {
return atomicBox.withValue { value in
return SignalProducer(value: value!)
.takeUntilReplacement(relaySignal)
.on(disposed: { self })
}
}
/// A lazily-initialized signal retaining the relay until termination.
///
/// Using this signal would prevent the relay from being deinitialized until
/// the source producer completes.
lazy var signal: Signal<Value, NoError> = { [unowned self] in
let strongSelf = self
return self.relaySignal.on(disposed: { strongSelf })
}()
init?(source producer: SignalProducer<Value, NoError>) {
atomicBox = Atomic(nil)
disposable = CompositeDisposable()
disposable += producer.start { [weak self, disposable, relayObserver] event in
switch event {
case let .Next(newValue):
self?.atomicBox.value = newValue
relayObserver.action(event)
case .Completed, .Interrupted:
relayObserver.action(event)
disposable.dispose()
case let .Failed(error):
fatalError("Receive unexpected error from a producer of `NoError` type: \(error)")
}
}
if atomicBox.value == nil {
return nil
}
}
deinit {
relayObserver.sendInterrupted()
disposable.dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment