You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
3.3 KiB
77 lines
3.3 KiB
//
|
|
// repeatWithBehavior.swift
|
|
// RxSwiftExt
|
|
//
|
|
// Created by Marin Todorov on 05/08/2017.
|
|
// Copyright © 2016 RxSwift Community. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import RxSwift
|
|
|
|
public typealias RepeatPredicate = () -> Bool
|
|
|
|
/*
|
|
Uses RepeatBehavior defined in retryWithBehavior
|
|
*/
|
|
|
|
/** Dummy error to use with catchError to restart the observable */
|
|
private enum RepeatError: Error {
|
|
case catchable
|
|
}
|
|
|
|
extension ObservableType {
|
|
|
|
/**
|
|
Repeats the source observable sequence using given behavior when it completes
|
|
- parameter behavior: Behavior that will be used when the observable completes
|
|
- parameter scheduler: Schedular that will be used for delaying subscription after error
|
|
- parameter shouldRepeat: Custom optional closure for decided whether the observable should repeat another round
|
|
- returns: Observable sequence that will be automatically repeat when it completes
|
|
*/
|
|
public func repeatWithBehavior(_ behavior: RepeatBehavior, scheduler: SchedulerType = MainScheduler.instance, shouldRepeat: RepeatPredicate? = nil) -> Observable<Element> {
|
|
return repeatWithBehavior(1, behavior: behavior, scheduler: scheduler, shouldRepeat: shouldRepeat)
|
|
}
|
|
|
|
/**
|
|
Repeats the source observable sequence using given behavior when it completes
|
|
- parameter currentRepeat: Number of the current repetition
|
|
- parameter behavior: Behavior that will be used in case of completion
|
|
- parameter scheduler: Schedular that will be used for delaying subscription after error
|
|
- parameter shouldRepeat: Custom optional closure for decided whether the observable should repeat another round
|
|
- returns: Observable sequence that will be automatically repeat when it completes
|
|
*/
|
|
internal func repeatWithBehavior(_ currentRepeat: UInt, behavior: RepeatBehavior, scheduler: SchedulerType = MainScheduler.instance, shouldRepeat: RepeatPredicate? = nil)
|
|
-> Observable<Element> {
|
|
guard currentRepeat > 0 else { return Observable.empty() }
|
|
|
|
// calculate conditions for bahavior
|
|
let conditions = behavior.calculateConditions(currentRepeat)
|
|
|
|
return concat(Observable.error(RepeatError.catchable))
|
|
.catch { error in
|
|
//if observable errors, forward the error
|
|
guard error is RepeatError else {
|
|
return Observable.error(error)
|
|
}
|
|
|
|
//repeat
|
|
guard conditions.maxCount > currentRepeat else { return Observable.empty() }
|
|
|
|
if let shouldRepeat = shouldRepeat, !shouldRepeat() {
|
|
// also return error if predicate says so
|
|
return Observable.empty()
|
|
}
|
|
|
|
guard conditions.delay != .never else {
|
|
// if there is no delay, simply retry
|
|
return self.repeatWithBehavior(currentRepeat + 1, behavior: behavior, scheduler: scheduler, shouldRepeat: shouldRepeat)
|
|
}
|
|
|
|
// otherwise retry after specified delay
|
|
return Observable<Void>.just(()).delaySubscription(conditions.delay, scheduler: scheduler).flatMapLatest {
|
|
self.repeatWithBehavior(currentRepeat + 1, behavior: behavior, scheduler: scheduler, shouldRepeat: shouldRepeat)
|
|
}
|
|
}
|
|
}
|
|
}
|