如何使用动态类型的Swift JSONDecode?

如何使用动态类型的Swift JSONDecode?,第1张

概述我的应用程序具有本地缓存​​,并从/向服务器发送/接收模型.所以我决定构建一个map [String:Codable.Type],基本上能够解码我在本地创建或从服务器接收的通用缓存上的任何内容. let encoder = JSONEncoder()let decoder = JSONDecoder()var modelNameToType = [String : Codable.Type]( 我的应用程序具有本地缓存​​,并从/向服务器发送/接收模型.所以我决定构建一个map [String:Codable.Type],基本上能够解码我在本地创建或从服务器接收的通用缓存上的任何内容.

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?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1008078.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-22
下一篇2022-05-22

发表评论

登录后才能评论

评论列表(0条)

    保存