Swift Combine 如何使用catch捕获网络错误回退加载本地缓存数据
正确实现方案
你需要的「网络请求失败后回退到本地缓存」的场景,天生适合用catch操作符实现,根本不需要用到combineLatest或者mergeMany,这两个操作符的能力和你的业务逻辑不匹配。
catch的错误处理逻辑
catch的作用是监听上游发布者的错误事件:
- 若上游(网络请求发布者)正常输出数据,
catch不会触发,直接把网络数据透传给下游 - 只有上游抛出错误时,
catch才会执行你传入的闭包,返回备用发布者(本地缓存读取发布者),用备用发布者的输出替代原来的失败流
你那个可以运行的写法本身就是正确的,补全你的仓储层方法如下即可:
func getPosts() -> AnyPublisher<[Post], Error> { dataSource.getPosts() .catch { error -> AnyPublisher<[Post], Error> in // 可选:只在网络类错误时回退本地,其他错误可以选择继续抛出 if let networkError = error as? NetworkError { print("网络请求异常,回退本地缓存:\(networkError)") return sharedPreferenceDataSource.getLocalPosts() } // 非网络错误可根据业务需求选择抛出或也走本地缓存 return Fail(error: error).eraseToAnyPublisher() } .eraseToAnyPublisher() }
为什么你最早的写法不生效
你最开始写的dataSource.getPosts().catch {sharedPreferenceDataSource.getLocalPosts()}没有返回整个Publisher链,也没有调用eraseToAnyPublisher()匹配方法的返回值类型,所以不会生效。
为什么combineLatest/mergeMany不适合你的需求
CombineLatest的作用是合并多个发布者的最新输出,当所有发布者都至少输出一个值后,会把多个值组装成元组发出,用这个操作符会同时触发网络请求和本地读取,无法实现「出错才回退」的逻辑MergeMany的作用是把多个发布者的输出合并到同一个流里,哪个发布者先输出就先发送哪个值,同样会同时触发两个请求,也不符合你「先请求网络,失败才读本地」的优先级逻辑
内容的提问来源于stack exchange,提问作者biggreentree
相关产品推荐
相关产品推荐

