Skip to content

Instantly share code, notes, and snippets.

@nubbel
Last active March 13, 2018 21:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nubbel/a71943f7d4a3bee7fb09133c4edd2eca to your computer and use it in GitHub Desktop.
Save nubbel/a71943f7d4a3bee7fb09133c4edd2eca to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import Foundation
protocol ObserverType {
associatedtype Element
func onNext(_ element: Element)
func onComplete()
func onError(_ error: Error)
}
final class AnyObserver<E>: ObserverType {
typealias Element = E
let _onNext: (Element) -> Void
let _onComplete: () -> Void
let _onError: (Error) -> Void
init<O: ObserverType>(_ observer: O) where O.Element == Element {
_onNext = observer.onNext
_onComplete = observer.onComplete
_onError = observer.onError
}
func onNext(_ element: Element) {
return _onNext(element)
}
func onComplete() {
return _onComplete()
}
func onError(_ error: Error) {
return _onError(error)
}
}
final class Observer<E>: ObserverType {
typealias Element = E
let _onNext: ((Element) -> Void)?
let _onComplete: (() -> Void)?
let _onError: ((Error) -> Void)?
init(onNext: ((Element) -> Void)? = nil, onComplete: (() -> Void)? = nil, onError: ((Error) -> Void)? = nil) {
_onNext = onNext
_onComplete = onComplete
_onError = onError
}
func onNext(_ element: Element) {
_onNext?(element)
}
func onComplete() {
_onComplete?()
}
func onError(_ error: Error) {
_onError?(error)
}
}
protocol CancellableType {
func cancel()
}
struct Cancellable: CancellableType {
let _cancel: (() -> Void)?
init(_ cancel: (() -> Void)? = nil) {
_cancel = cancel
}
func cancel() {
_cancel?()
}
}
protocol ObservableType {
associatedtype Element
func subscribe<O: ObserverType>(_ observer: O) -> CancellableType where O.Element == Element
}
class Observable<E> : ObservableType {
typealias Element = E
func subscribe<O: ObserverType>(_ observer: O) -> CancellableType where O.Element == Element {
fatalError("not implemented")
}
static func create(_ subscribe: @escaping (AnyObserver<Element>) throws -> CancellableType) -> Observable<E> {
return AnonymousObservable(subscribe)
}
}
class AnonymousObservable<E>: Observable<E> {
private let _subscribe: (AnyObserver<Element>) throws -> CancellableType
init(_ subscribe: @escaping (AnyObserver<Element>) throws -> CancellableType) {
_subscribe = subscribe
}
override
func subscribe<O: ObserverType>(_ observer: O) -> CancellableType where O.Element == Element {
do {
return try _subscribe(AnyObserver(observer))
}
catch let error {
observer.onError(error)
return Cancellable()
}
}
}
class RetryObservable<E>: Observable<E> {
private var retryCount: Int
private let wrappedObservable: Observable<E>
init(retryCount: Int, wrappedObservable: Observable<E>) {
self.retryCount = retryCount
self.wrappedObservable = wrappedObservable
}
override
func subscribe<O: ObserverType>(_ observer: O) -> CancellableType where O.Element == Element {
var subscription: CancellableType!
var handler: Observer<E>!
handler = Observer<E>(
onNext: observer.onNext,
onComplete: observer.onComplete,
onError: { error in
guard self.retryCount > 0 else {
observer.onError(error)
return
}
self.retryCount -= 1
subscription?.cancel()
subscription = self.wrappedObservable.subscribe(handler)
}
)
subscription = wrappedObservable.subscribe(handler)
return Cancellable {
subscription?.cancel()
}
}
}
// Usage example
enum MyError: Error {
case SomethingWentWrong
case Oops
}
var count = 0
let observable = Observable<Int>.create { observer in
count += 1
if count < 3 {
throw MyError.Oops
}
observer.onNext(count)
return Cancellable {
print("cancel")
}
}
let retryObservable = RetryObservable(retryCount: 5, wrappedObservable: observable)
let observer = Observer<Int>(
onNext: { print("next:", $0) },
onComplete: { print("complete") },
onError: { print("error:", $0 )}
)
let subscription = retryObservable.subscribe(observer)
subscription.cancel()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment