如何在Interactor中组合Local/Remote的AnyPublisher?解决flatMap报错
问题与解决
我正在编写一个Interactor文件,需要实现优先从本地存储获取数据、本地无数据则从远程存储获取的逻辑。数据流向如下:
ViewModel(GetCode()) >> Interactor(GetCode()-> AnyPublisher<String, Error>) >> Local/Remote Storage -> AnyPublisher<String?, Error>)
LocalDataSourceProvider提供的方法:
func fetchCode(id: String) -> AnyPublisher<String?, Error>
若本地返回nil,则调用RemoteDataSourceProvider的方法:
func fetchCode(id: String) -> AnyPublisher<String, Error>
按照建议修改代码后:
local.fetchCode(voucherId).flatMap { if let code = $0 { return Just(code).eraseToAnyPublisher() } return remote.fetchCode(Id: Id).eraseToAnyPublisher() }
出现报错,翻译为:
没有匹配的'flatMap'候选函数能生成预期的上下文结果类型'AnyPublisher<String?, Error>'
问题原因
报错核心是flatMap闭包返回的Publisher类型不统一:
- 本地分支返回的
Just(code)是AnyPublisher<String, Never>类型,错误类型为Never,且输出是可选性不匹配的非可选String - 远程分支返回的是
AnyPublisher<String, Error>,输出同样是非可选String - 外层预期的结果类型是
AnyPublisher<String?, Error>,三者类型完全不匹配,导致编译器无法找到合适的flatMap重载
修复后的代码
local.fetchCode(id: voucherId) .flatMap { localCode -> AnyPublisher<String?, Error> in if let code = localCode { // 将非可选String转为可选,同时设置错误类型为Error,统一分支类型 return Just(code as String?) .setFailureType(to: Error.self) .eraseToAnyPublisher() } else { // 将远程返回的非可选String转为可选,对齐输出类型 return remote.fetchCode(id: voucherId) .map { $0 as String? } .eraseToAnyPublisher() } }
关键调整点
- 统一输出类型:把本地和远程的输出都转为
String?,匹配外层预期的泛型参数 - 统一错误类型:给
Just添加setFailureType(to: Error.self),确保错误类型和远程分支一致 - 明确闭包返回类型:显式指定闭包返回
AnyPublisher<String?, Error>,帮助编译器准确推导
内容的提问来源于stack exchange,提问作者pankaj
相关产品推荐
相关产品推荐

