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作为触发器,.sendload:中设置

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
}
}

相关内容

  • 没有找到相关文章

最新更新