在Combine中如何映射为Encodable类型解决Publisher类型转换报错
问题原因
你协议中output指定的返回类型是Published<Encodable>.Publisher这一具体发布者类型,但你对handler.$userTextOutput做map转换后得到的是Publishers.Map<Published<String>.Publisher, Encodable>类型,二者不属于同一具体类型,因此触发类型不匹配报错。
解决方案
- 首先修改协议定义,不要限定
output为具体的Published发布者类型,改用类型抹除后的AnyPublisher<Encodable, Never>,适配不同输入字段的发布者转换场景。 - 补充实现类型擦除的
AnyEncodable结构体,避免直接返回Encodable协议类型时无法正常编码的问题(Encodable作为类型本身不遵循Encodable协议,直接使用会触发编码错误)。 - 对map转换后的发布者调用
eraseToAnyPublisher()完成类型抹除,匹配协议定义的返回类型。
完整修改后代码
import Combine // 类型擦除的Encodable包装,解决协议类型无法直接编码的问题 struct AnyEncodable: Encodable { private let value: Encodable init(_ value: Encodable) { self.value = value } func encode(to encoder: Encoder) throws { try value.encode(to: encoder) } } protocol FieldResponseModifying { var id: String { get } // 改用类型抹除的发布者,不限制具体发布者类型 var output: AnyPublisher<AnyEncodable, Never> { get } } struct SampleTextWrapper: FieldResponseModifying { var output: AnyPublisher<AnyEncodable, Never> { handler.$userTextOutput .map { AnyEncodable($0) } .eraseToAnyPublisher() } let id = UUID().uuidString let handler = SampleTextHandler() } class SampleTextHandler { @Published var userTextOutput = "" init () { } }
扩展说明
如果你的输入字段支持日期、数字等其他类型,只需要在对应Wrapper的map转换中把值包装成AnyEncodable即可,所有字段的输出都可以统一为AnyPublisher<AnyEncodable, Never>类型,方便后续合并所有输入流、统一编码上传。
内容的提问来源于stack exchange,提问作者Dr. Mr. Uncle
相关产品推荐
相关产品推荐

