Swift中基于Codable的请求模型JSON编码继承实现难题
解决Swift中RequestType协议无法直接使用JSONEncoder的问题
我完全懂你碰到的这个棘手问题——用类当父类会逼着所有子类去实现根本不需要的解码初始化方法,换成协议的话,又没法在request函数里直接编码协议类型的实例,这确实是Swift里Codable和协议类型结合时的典型痛点。
下面给你两种实用的解决方案,你可以根据自己的实际需求来选:
方案一:把request函数改成泛型函数
这是最直接的解决思路,利用泛型约束让编译器明确知道传入的是具体的、遵循RequestType的类型,这样JSONEncoder就能正常工作了:
// 父类型协议 protocol RequestType: Codable { } // 模型类 class InitiateSignInRequest: RequestType { var phone: String init(_ phone: String) { self.phone = phone } } // 处理所有模型类的泛型函数 private func request<T: RequestType>(data: T) throws { let encoder = JSONEncoder() let encodedData = try encoder.encode(data) if let postPayload = String(data: encodedData, encoding: .utf8) { // 这里写你的postPayload处理逻辑 print(postPayload) } } // 调用示例 let signInReq = InitiateSignInRequest("1234567890") try? request(data: signInReq)
改成泛型后,编译器能确定T是具体的遵循Codable的类型,自然就能正常用JSONEncoder了,同时子类也不用额外实现init(from decoder: Decoder)(除非你有自定义解码的需求)。
方案二:使用类型擦除(Type Erasure)
如果你因为某些限制不能把函数改成泛型,可以创建一个类型擦除的包装器,把任意RequestType实例包装成一个遵循Codable的具体类型:
// 父类型协议 protocol RequestType: Codable { } // 类型擦除的包装器 struct AnyRequestType: Codable { private let encodeFunc: (JSONEncoder) throws -> Data init<T: RequestType>(_ request: T) { self.encodeFunc = { encoder in try encoder.encode(request) } } func encode(to encoder: Encoder) throws { let data = try encodeFunc(JSONEncoder()) var container = encoder.singleValueContainer() try container.encode(data) } // 如果不需要解码功能,可以忽略这个初始化方法;如果需要,得额外处理类型标识 init(from decoder: Decoder) throws { fatalError("Decoding requires additional type identifier handling") } } // 处理函数 private func request(data: AnyRequestType) throws { let encoder = JSONEncoder() let encodedData = try encoder.encode(data) if let postPayload = String(data: encodedData, encoding: .utf8) { // 处理逻辑 print(postPayload) } } // 调用示例 let signInReq = InitiateSignInRequest("1234567890") let wrappedReq = AnyRequestType(signInReq) try? request(data: wrappedReq)
这种方式适合你必须用协议类型作为参数的场景,但如果需要解码,还得额外存储类型信息,相对麻烦一些。
总结
如果没有特殊限制,方案一的泛型函数是最简洁高效的,既解决了编码问题,又避免了子类的冗余代码。
内容的提问来源于stack exchange,提问作者Aviran
相关产品推荐
相关产品推荐

