Alamofire + Combine + MVVM请求示例

编程入门 行业动态 更新时间:2024-10-25 12:29:04
本文介绍了Alamofire + Combine + MVVM请求示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

在我的视图控制器中,我有一个属性 items ,可以订阅并呈现我的视图.

in my view controller I have a property items to which I have a subscription and rendering my view.

对于这个视图控制器,我有一个视图模型,其中有类似如下的加载方法:

For this view controller I have a view model where I have load method like:

@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 方法时,它都会订阅一次,我认为不应该这样.

My user can load multiple times and as you can see It will subscribe each time when load method is called, which I think should not be like this.

我试图为我的视图模型引入属性:

I tried to introduce property for my view model:

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 ,因此我无法进行初始绑定,因此它将无法订阅.

But in this case I can't make initial binding since initial value is nil hence it won't subscribe.

另一个问题是关于处理来自加载的错误,我是否需要在视图模型内部具有 error 的属性,或者是否可以通过方法为 $ items 抛出错误?

Another question is about handling error from load, do I need to have property for error inside view model or is there way I can rethrow an error for $items?

推荐答案

您可以在 init 中设置单个订阅,并使用 PassthroughSubject 作为触发器,并使用.send 内 load :

You can setup a single subscription in init with a PassthroughSubject as a trigger, and .send inside 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) }

我无法告诉您如何处理该错误,因为该错误非常具体,并且可能是主观的,例如错误应该终止订阅吗?您打算处理可能的多个错误吗?

I can't tell you how to handle the error, since it's very case specific and probably subjective, e.g. should an error terminate the subscription? do you plan to handle possible multiple errors?

如果您希望永不失败,但仍会作为错误来处理错误,则可以返回 结果 ,它将捕获值或错误.这样,管道的失败类型可能为 Never ,因此它永远不会因错误而终止.然后,将结果包装在 .sink :

If you want to never fail, but still handle an error as a side effect, you can return Result, which would capture both value or error. This way, the pipeline could have a failure type of Never, so it would never terminate due to error. Then you'd unwrap the result inside the .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 } }

更多推荐

Alamofire + Combine + MVVM请求示例

本文发布于:2023-11-26 03:31:08,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1632463.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:示例   Alamofire   Combine   MVVM

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!