Swift Combine - Result
iOS
Swift
Combine
Result
Reactive Programming
我們有一個 Combine 取得網路料的 function
func getData() -> AnyPublisher<Model, ApiError> {
URLSession.shared.dataTaskPublisher(for: URL(string: "https://xxx.xx/xx")!)
.asError(type: ApiError.self, { .url(error: $0) })
.map { $0.data }
.decode(type: Model.self, decoder: JSONDecoder())
.asError(type: ApiError.self, { .decode(error: $0)})
.eraseToAnyPublisher()
}
要拿到 error 或是 api 回來的 model,我們就會用 Sink 這一個 Operator
Combine 的 sink operator 有兩個
func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
兩者的差別是 一個有 completion block 一個沒有
沒有 completion block 只能在 Output type == Never 才能使用
如果我們把 combine 用在網路層,我們只會收到一次資料,但是卻要兩個 block
像是這個樣子
getData().sink { state in
switch state {
case .finished:
print("finished")
case let .failure(error):
print(error)
}
} receiveValue: { model in
print(model)
}.store(in: &disposables)
可是在 api 只回應一次內容的情境下,我們根本不會在乎 finished 這件事,因為拿到 error 或者是拿到 Model 就可以代表 finished
但是我們又不能使用只有 receiveValue block 的 sink Operator
因為我們的 api 是有機會有 error,不符合 Output type == Never
若是硬是要用怎麼辦呢
只好自己寫一個 operator,把原本的 Output 跟 Error 包成Result
這樣使用起來就會簡單多了
getData()
.transformToResult()
.sink { result in
switch result {
case let .failure(error):
print(error)
case let .success(model):
print(model)
}
}
打完收工