
let encoder = JsONEncoder()let decoder = JsONDecoder()var modelnameToType = [String : Codable.Type]()modelnameToType = ["ContactModel": ContactModel.Self,"AnythingModel" : AnythingModel.Self,...]
无论我在App上创建什么,我都可以成功编码并存储在缓存中,如下所示:
let contact = ContactModel(name: "John")let data = try! encoder.encode(contact)CRUD.shared.storekey(key: "ContactModel",contact)
我想像这样解码:
let result = try! decoder.decode(modelnameToType["ContactModel"]!,from: data)
但我得到错误:
Cannot invoke ‘decode’ with an argument List of type (Codable.Type,
from: Data)
我究竟做错了什么?任何帮助表示赞赏
修复类型有效,并解决任何本地请求,但不能解决远程请求.
let result = try! decoder.decode(ContactModel.self,from: data)
联系型号:
struct ContactModel: Codable { var name : String} 对于远程请求,我会有这样的函数:
func buildAnswer(keys: [String]) -> Data { var result = [String:Codable]() for key in keys { let data = CRUD.shared.restoreKey(key: key) let item = try decoder.decode(modelnameToType[key]!,from: data) result[key] = item } return try encoder.encode(result) } …如果我解决了解码问题.任何帮助赞赏.
解决方法 Codable API围绕编码和解码为具体类型而构建.但是,你想要的往返不应该知道任何具体的类型;它只是将异构JsON值连接成一个JsON对象.因此,在这种情况下,JsONSerialization是一个更好的工具,因为它处理Any:
import Foundation// I would consIDer lifting your String keys into their own type btw.func buildAnswer(keys: [String]) throws -> Data { var result = [String: Any](minimumCapacity: keys.count) for key in keys { let data = CRUD.shared.restoreKey(key: key) result[key] = try JsONSerialization.JsonObject(with: data) } return try JsONSerialization.data(withJsONObject: result)} 话虽如此,您仍然可以使用JsONDecoder / JsONEncoder进行此 *** 作 – 但它需要相当多的类型擦除样板.
例如,我们需要一个符合encodable的包装类型,如encodable doesn’t conform to itself:
import Foundationstruct AnyCodable : encodable { private let _encode: (Encoder) throws -> VoID let base: Codable let codableType: AnyCodableType init<Base : Codable>(_ base: Base) { self.base = base self._encode = { var container = struct AnyCodableType { private let _decodeJsON: (JsONDecoder,Data) throws -> AnyCodable // repeat for other decoders... // (unfortunately I don't belIEve there's an easy way to make this generic) // let base: Codable.Type init<Base : Codable>(_ base: Base.Type) { self.base = base self._decodeJsON = { decoder,data in AnyCodable(try decoder.decode(base,from: data)) } } func decode(from decoder: JsONDecoder,data: Data) throws -> AnyCodable { return try _decodeJsON(decoder,data) }}.singleValueContainer() try container.encode(base) } self.codableType = AnyCodableType(type(of: base)) } func encode(to encoder: Encoder) throws { try _encode(encoder) }} 我们还需要一个包装器来捕获可用于解码的具体类型:
func decode<T : Decodable>(_ type: T.Type,from data: Data) throws -> T
我们不能简单地将Decodable.Type传递给JsONDecoder
enum Modelname : String { case contactModel = "ContactModel" case anythingModel = "AnythingModel" var modelType: AnyCodableType { switch self { case .contactModel: return AnyCodableType(ContactModel.self) case .anythingModel: return AnyCodableType(AnythingModel.self) } }} 当T是协议类型时,type:参数采用.Protocol元类型,而不是.Type元类型(有关详细信息,请参阅this Q&A).
我们现在可以为我们的键定义一个类型,使用一个modelType属性返回一个可以用来解码JsON的AnyCodableType:
func buildAnswer(keys: [Modelname]) throws -> Data { let decoder = JsONDecoder() let encoder = JsONEncoder() var result = [String: AnyCodable](minimumCapacity: keys.count) for key in keys { let rawValue = key.rawValue let data = CRUD.shared.restoreKey(key: rawValue) result[rawValue] = try key.modelType.decode(from: decoder,data: data) } return try encoder.encode(result)} 然后为往返做这样的事情:
这可能更好地设计为使用Codable而不是它(可能是一个表示您发送到服务器的JsON对象的结构,并使用键路径与缓存层交互),但不知道更多有关CRUD.shared和你如何使用它;很难说.
总结以上是内存溢出为你收集整理的如何使用动态类型的Swift JSONDecode?全部内容,希望文章能够帮你解决如何使用动态类型的Swift JSONDecode?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)