swift - 具有泛型类型的可观察扩展
问题描述
语境
我想将其包装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 { request in
Observable<UploadElement<Result>>.create { observer in
request.response { response in
do {
observer.on(.next(.response(/* decode here */)))
observer.on(.completed)
} catch let error {
observer.on(.error(error))
}
}.uploadProgress { progress in
observer.on(.next(.progress(progress.fractionCompleted)))
}
.resume()
return Disposable.create { request.cancel() }
}
}
}
现在我想对 an 进行扩展,Observable<UploadEment<Result>>
以便有更好的通知方式。
基本上它会是:
service.upload(url: ..., 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: { element in
switch element {
case .progress(let progress): progressCompletion(progress)
case .response: return
}
})
}
func result(resultCompletion: @escaping (Result) -> Void) -> Self {
return self.do(onNext: { element in
switch element {
case .response(let result): resultCompletion(result)
case .progress: return
}
})
}
}
我尝试了多种变体,但我得到的错误是:
- 找不到“范围内的结果”
- 引用泛型类型...必需参数
有可能实现这样的目标吗?
解决方案
您只需将 where 子句从类范围移动到函数范围(如下所示)。
也就是说,我不认为像这样在流中间突破单子是“一种更好的通知方式”。
最好将您的 Observable 分成两个流并订阅每个流:
extension ObservableType {
func progress<Resource>() -> Observable<Double> where Element == UploadElement<Resource> {
self.compactMap { element in
switch element {
case let .progress(progress):
return progress
case .response:
return nil
}
}
}
func result<Resource>() -> Observable<Resource> where Element == UploadElement<Resource> {
self.compactMap { element in
switch element {
case .progress:
return nil
case let .response(resource):
return resource
}
}
}
}
有了上述内容,您现在可以执行以下操作:
let response = service.upload(url: ..., parts: ...)
.share()
response
.progress()
.subscribe(onNext: { progress in /*...*/ })
.disposed(by: disposeBag)
response
.result()
.subscribe(onNext: { result in /*...*/ })
.dispose(by: disposeBag)
现在您没有任何空订阅。
推荐阅读
- javascript - 多个按钮 - for 循环不会执行,所以按钮不起作用 - javascript
- python - curses.getstr 具有预先填充的值
- android - 找不到 com.android.tools.build:gradle:6.5
- python - 如何用其他字典中存在的某些值替换字典中的占位符?
- python - Python dict解包运算符不在构造函数中解包字符串
- r - 如何识别不合逻辑的字符串/句子
- python-3.x - 如何从表格数据中获取数据然后打印一条消息
- 3d - gnuplot:如何避免依赖视角的半透明 3D 表面?
- javascript - 如何在角度中的每 2 个字符后自动插入/添加冒号 (:)
- php - 致命错误:未捕获的错误:调用未定义的方法 mysqli::execute()