Вот что я закончил, глядя на оба ваших примера кода:
Сначала вот точка использования:
let request = searchBar.rx.text
.unwrap()
.map { URLRequest.search(forQuery: $0) }
let networkRequest = createRequest(forType: MyType.self)
let state = request
.flatMap(networkRequest)
state
.map { $0.isLoading }
.bind(to: loaderView.isOffline)
.disposed(by: bag)
state
.map { $0.data }
.unwrap()
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: bag)
state
.map { $0.error }
.unwrap()
.subscribe(onNext: showAlert)
.disposed(by: bag)
Вот код поддержки для выше:
enum RequestState<T> {
case loading
case loaded(T)
case error(Error)
var isLoading: Bool {
guard case .loading = self else { return false }
return true
}
var data: T? {
guard case let .loaded(t) = self else { return nil }
return t
}
var error: Error? {
guard case let .error(e) = self else { return nil }
return e
}
}
Вы увидите, что вышеприведенное перечисление RequestState
является объединением обоих типов RequestState
, которые вы показали в своем примере.Перечисление облегчает создание объекта, в то время как вычисленные свойства облегчают извлечение информации.
func createRequest<T>(forType type: T.Type, session: URLSession = URLSession.shared) -> (URLRequest) -> Observable<RequestState<T>> where T: Decodable {
return { request in
return Observable.create { observer in
observer.onNext(.loading)
let disposable = session.rx.data(request: request)
.subscribe { event in
switch event {
case let .error(error):
observer.onNext(.error(error))
case let .next(data):
do {
let item = try JSONDecoder().decode(type, from: data)
observer.onNext(.loaded(item))
}
catch {
observer.onNext(.error(error))
}
case .completed:
observer.onCompleted()
}
}
return Disposables.create([disposable])
}
}
}
Выше приведена заводская функция.Вы используете его для создания функции, которая знает, как делать сетевые запросы для соответствующего типа.Вспомните в коде, где он используется, у меня был let networkRequest = createRequest(forType: MyType.self)
.Эта строка создает функцию networkRequest
, которая принимает URLRequest и возвращает Observable, специализированный для рассматриваемого типа.
Когда на Observable из networkRequest
подписана, онанемедленно вытолкнет .loading
чехол, затем сделает запрос.Затем он будет использовать ответ для выталкивания .loaded(T)
или .error(Error)
в зависимости от результатов.
Лично я более склонен использовать что-то вроде системы ActivityIndicator из примеров в RxSwiftвместо хранилища.