Context
<我想把Alamofire.upload包裝成一個可觀察的物件,并有關于上傳進度的資訊。
為此,我創建了一個自定義的UploadElement,它是一個列舉,代表進度和值或結果。到目前為止,我有:
enum UploadElement< Result> where Result: Codable {
case progress(Double)
case response(Result)
}
private func buildUploadRequest(url: URL, parts: [Data]) -> Observable<UploadRequest> {
let uploadRequest = manager.upload(
multipartFormData: { multipartFormData in /* build multipart */ },
to: url
)
return Observable.just(uploadRequest)
}
func upload<Result。Codable>(url: URL, parts: [Data]) -> Observable<UploadElement<Result> > {
buildUploadRequest(url: url, parts: parts)
.flatMap { 請求 in
Observable<UploadElement<Result>.create { observer in.
request.response { response in.
do {
observer.on(.next(.response(/* decode here */) ))
觀察者.on(.completed)
} catch let error {
observer.on(.error(error))
}
}.uploadProgress { progress in
observer.on(.next(.progress(progress.fractionCompleted)))
}
.恢復()
return Disposable.create { request.cancel() }
}
}
現在我想在Observable<UploadEment<Result>>上有一個擴展,以便有一個更好的方式來獲得通知。
基本上,它將是:
service.upload(url: .../span>, parts: ...)
.progress { progress in /* */ }
.result { result in /* */ }
.subscribe()
.dispose(by: disposeBag)
為了做到這一點,我嘗試了:
extension ObservableType where Element == UploadElement< Resource> {
func progress(progressCompletion: @escaping (Double) -> Void) -> Self {
return self.do(onNext: {元素in
switch元素 {
case .progress(let progress) : progressCompletion(progress)
case .response: 回傳。
}
})
}
func result(resultCompletion: @escaping (Result) -> Void) -> Self {
return self.do(onNext: {元素in
switch元素 {
case .response(let result): resultCompletion( result)
case .progress: 回傳。
}
})
}
}
我嘗試了多種變體,但我得到的錯誤是:
- 無法找到'范圍內的結果'
- 無法找到'范圍內的結果' 。
- 參考通用型別...需要引數 。
是否有可能做到?
有可能實作這樣的事情嗎?
uj5u.com熱心網友回復:
你只需要將where子句從類的范圍下移到函式范圍(如下圖所示)。
盡管如此,我不認為在流的中間像這樣突破單體是 "一種更好的通知方式"。
更好的方法是將你的 Observable 分成兩個流,并分別訂閱它們:
extension ObservableType {
func progress<Resource> () -> Observable<Double> where Element == UploadElement<Resource> {
self.compactMap { element in.
switch元素 {
case let .progress(progress):
return progress
case .response:
return nil
}
}
}
func result<Resource> () -> Observable<Resource> where Element == UploadElement<Resource> {
self.compactMap { element in.
switch元素 {
case .progress:
return nil nil
case let .response( resource):
return resource
}
}
}
}
有了上述內容,你現在可以做這樣的事情:
let response = service.upload(url: ..., parts: ...)
.分享()
回應
.progress()
.訂閱(onNext: { progress in /*...*/ })
.處置(by: disposeBag)
回應
.result()
.subscribe(onNext: { 結果 in /*...*/ })
.dispose(by: disposeBag)
現在你沒有任何空的訂閱了。
uj5u.com熱心網友回復:
我發現了一個可以作業的東西:
extension ObservableType {
func progress<O: Codable>(progressCompletion: @escaping (Double) -> Void) -> Observable<UploadElement<O> > where Element == UploadElement<O> {
return self.do(onNext: {元素in
if case .progress(let progress) = element {
progressCompletion(progress)
}
})
}
func response<O: Codable>(responseCompletion: @escaping (O) -> Void) -> Observable<UploadElement<O> > where Element == UploadElement<O> {
return self.do(onNext: {元素in
if case .response(let response) = element {
回應完成(response)
}
})
}
}
現在我可以使用 "計劃中的 "api了:
。service.update(data: /* ... */)
.progress { progress in /* */ }
.response { result in /* */ }
.subscribe(
one rror: { error in /* */ } .
)
.dispose(by: disposeBag)
然而正如Daniel 提到的,這可能不是 "更好的被通知方式"。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/332323.html
標籤:
