Skip to content

Instantly share code, notes, and snippets.

@daltonclaybrook
Last active April 23, 2020 15:20
Show Gist options
  • Save daltonclaybrook/177adda6b3e07c36a2062f21089a5726 to your computer and use it in GitHub Desktop.
Save daltonclaybrook/177adda6b3e07c36a2062f21089a5726 to your computer and use it in GitHub Desktop.
import RxSwift
/// This type is similar to `BehaviorRelay`, but it allows for mutating an element in-place
/// rather than assigning a new one.
///
/// This is useful for large copy-on-write containers. For example, it's less expensive to append
/// an element to an `Array` with 1M entries than it is to make a new `Array` by concatenating it with
/// a second `Array` with one element.
public final class MutableRelay<Element>: ObservableType {
public private(set) var value: Element
private let subject = ReplaySubject<Element>.create(bufferSize: 1)
private let lock = NSRecursiveLock()
public init(value: Element) {
self.value = value
subject.onNext(value)
}
public func subscribe<Observer>(_ observer: Observer) -> Disposable where Observer: ObserverType, Element == Observer.Element {
subject.subscribe(observer)
}
public func accept(_ element: Element) {
modify { $0 = element }
}
public func modify(block: (inout Element) -> Void) {
lock.lock(); defer { lock.unlock() }
block(&value)
subject.onNext(value)
}
}
extension ObservableType {
public func bind<Element>(to relay: MutableRelay<Element>) -> Disposable where Self.Element == Element {
subscribe { event in
switch event {
case let .next(element):
relay.accept(element)
case .error, .completed:
break
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment