如何解决Alamofire + Combine + MVVM请求示例
在我的视图控制器中,我有一个属性items
,我对其进行了订阅并呈现了我的视图。
对于这个视图控制器,我有一个视图模型,其中有类似如下的加载方法:
@Published private(set) var items: [Item] = []
func load(params: [String: Any] = [:]) {
self.isLoading = true
self.subscription = WebRepo().index(params: params).sink(receiveCompletion: { [weak self] (completion) in
switch completion {
case .failure(let error):
print("Error is: \(error.localizedDescription)")
default: break
}
self?.isLoading = false
},receiveValue: { [weak self] (response) in
self?.items = response.data
})
}
我的WebRepo
如下:
final class WebRepo {
func index(params: [String: Any]) -> AnyPublisher<MyResponse<[Item]>,Error> {
let url = URL(...)
return AF.request(url,method: .get,parameters: params)
.publishDecodable(type: MyResponse<[Item]>.self)
.tryCompactMap { (response) -> MyResponse<[Item]>? in
if let error = response.error { throw error }
return response.value
}
.eraseToAnyPublisher()
}
}
我的用户可以加载多次,如您所见,每次调用load
方法时,它都会订阅一次,我认为不应该这样。
我试图为视图模型引入属性:
private var indexResponse: AnyPublisher<MyResponse<[Item]>,Error>?
//And my load becomes
func load(params: [String: Any] = [:]) {
self.isLoading = true
self.indexResponse = WebRepo().index(params: params)
}
但是在这种情况下,由于初始值为nil
,因此我无法进行初始绑定,因此它将无法订阅。
另一个问题是关于处理来自加载的错误,我是否需要在视图模型内部拥有error
的属性,还是可以通过一种方式重新抛出$items
的错误?
解决方法
您可以在init
中设置单个订阅,并以PassthroughSubject
作为触发器,并在.send
内部设置load
:
private var cancellables: Set<AnyCancellable> = []
private let loadTrigger = PassthroughSubject<[String: Any],Never>()
init(...) {
loadTrigger
//.debounce(...) // possibly debounce load requests
.flatMap { params in
WebRepo().index(params: params)
}
.sink(
receiveCompletion: {/* ... */},receiveValue: {/* ... */})
.store(in: &cancellables)
}
func load(params: [String: Any] = [:]) {
loadTrigger.send(params)
}
我无法告诉您如何处理该错误,因为该错误非常具体,并且可能是主观的,例如错误应该终止订阅吗?您打算处理可能的多个错误吗?
如果您希望永不失败,但仍会作为错误处理错误,则可以返回Result
,该错误将捕获值或错误。这样,流水线的失败类型可能为Never
,因此它永远不会因错误而终止。然后,您将结果包装在.sink
内:
loadTrigger
.flatMap { params -> AnyPublisher<Result<MyResponse<[Item]>,Error>,Never> in
WebRepo().index(params: params)
.map { .success($0) }
.catch { Just(.failure($0)) }
.eraseToAnyPublisher()
}
.sink { [weak self] result in
switch result {
case success(let response):
self?.items = response.data
case failure(let err):
// do something with the error
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。