我一直试图了解rxSwift。我遇到了请求问题,并希望以一种好的方式来实现它。目前,我正在使用以下代码:
enum RequestState<T> {
case loading
case loaded(T)
case error(Error)
}
struct Response<T: Decodable>: Decodable {
let data: T
let error: ResponseError?
}
searchBar.rx.text.asObservable()
.flatMap { self.provider.rx.request(Request(query: $0)) }
.map({ RequestState<Response<Bool>>.loaded($0) })
.asDriver(onErrorRecover: { error in
return Driver.just(.error(error))
})
.startWith(.loading)
.drive(onNext: { state in
switch state {
case .loading: ()
case .loaded(let response): ()
case .error(let error): ()
}
})
.disposed(by: disposeBag)
这很好,但不太方便处理数据和请求状态。我在rxSwift演示项目中看到了以下代码。
struct RequestState<T: Decodable> {
let isLoading: Bool
let data: T
let error: ResponseError?
}
let state = viewModel.requestMethod()
state
.map { $0.isLoading }
.drive(self.loaderView.isOffline)
.disposed(by: disposeBag)
state
.map { $0.data }
.drive(tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
state
.map { $0.error }
.drive(onNext: { error in
showAlert(error)
})
.disposed(by: disposeBag)
以下方法中的问题,在这里我无法理解Rx魔术:
func requestMethod() -> Driver<RequestState> {
// supper code
}
有人可以建议我在这里做什么吗?
答案 0 :(得分:0)
这是我在查看两个代码示例时得出的结论:
首先是使用要点:
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)
的代码。这行代码生成 function networkRequest
,该函数接受URLRequest并返回专门用于所讨论类型的Observable。
订阅networkRequest
中的Observable时,它将立即推出.loading
案例,然后发出请求。然后它将使用响应根据结果推出.loaded(T)
或.error(Error)
。
我个人更倾向于使用RxSwift存储库中示例中的ActivityIndicator系统之类的东西。