Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Decodable解码JSON嵌套字典并使用核心数据存储_Json_Swift_Core Data_Decodable - Fatal编程技术网

使用Decodable解码JSON嵌套字典并使用核心数据存储

使用Decodable解码JSON嵌套字典并使用核心数据存储,json,swift,core-data,decodable,Json,Swift,Core Data,Decodable,我有以下JSON结构: { "base": "USD", "date": "2020-04-24", "rates": { "CAD": 1.4049074074, "EUR": 0.9259259259 } } 我想将其解析为一个类并将其存储在核心数据中: class CurrencyRate: NSManagedObject, Decodable { enum CodingKeys: String, CodingKey { case

我有以下
JSON
结构:

{
  "base": "USD",
  "date": "2020-04-24",
  "rates": {
    "CAD": 1.4049074074,
    "EUR": 0.9259259259
  }
}
我想将其解析为一个类并将其存储在
核心数据中

class CurrencyRate: NSManagedObject, Decodable {
    enum CodingKeys: String, CodingKey {
        case base
        case date
        case rates
    }

    @NSManaged public var base: String
    @NSManaged public var date: Date
    @NSManaged public var rates: [String:Double]

    required convenience init(from decoder: Decoder) throws {
        ...
    }
根据我阅读的内容,为了在核心数据中存储
费率
字段,我必须创建另一个这样的实体,并创建一对多关系:

class SubCurrencyRate: NSManagedObject, Decodable {
    enum CodingKeys: String, CodingKey {
        case currency
        case rate
    }

    @NSManaged public var currency: String
    @NSManaged public var rate: Double

    required convenience init(from decoder: Decoder) throws {
        ...
    }
CurrencyRate
类中的
rates
字段将是:
@NSManaged public var rates:[SubCurrencyRate]

问题是我不知道如何将带有动态键的嵌套json解析到这些类中。怎样才能做到呢

一般来说,我如何解码JSON的这一部分:

"rates": {
  "CAD": 1.4049074074,
  "EUR": 0.9259259259
}
进入许多
次货币比率
对象?

我不久前写了一篇关于这方面的文章。
长话短说:我建议使用DTO解码到CoreData模型中。考虑到CoreData模型总是绑定到一个上下文(在从JSON解码时没有上下文),使用表示JSON的简单结构,然后从这些结构创建CoreData模型就更容易了。

无需
次货币利率
符合
可解码
,但您必须声明相反的关系(也在数据模型中!)

为了能够在核心数据中直接解析JSON,请声明两个扩展

extension CodingUserInfoKey {
    static let context = CodingUserInfoKey(rawValue: "context")!
}

extension JSONDecoder {
    convenience init(context: NSManagedObjectContext) {
        self.init()
        self.userInfo[.context] = context
    }
}
CurrencyRate
中,您必须在
init中将对多关系声明为
Set
(从decoder
解码费率字典并将其映射到
SubCurrencyRate
实例。如果模型中正确定义了关系,则会自动填充属性以及反向关系

class CurrencyRate: NSManagedObject, Decodable {
    enum CodingKeys: String, CodingKey { case base, date, rates }

    @NSManaged public var base: String
    @NSManaged public var date: Date
    @NSManaged public var rates: Set<SubCurrencyRate>

    required convenience init(from decoder: Decoder) throws {

        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: No object context!") }
        let entity = NSEntityDescription.entity(forEntityName: "CurrencyRate", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        base = try values.decode(String.self, forKey: .base)
        date = try values.decode(Date.self, forKey: .date)
        let ratesData = try values.decode([String:Double].self, forKey: .rates)
        for (key, value) in ratesData {
            let subCurrencyRate = SubCurrencyRate(context: context)
            subCurrencyRate.currency = key
            subCurrencyRate.rate = value
            subCurrencyRate.currencyRate = self
        }
    }
}
class CurrencyRate:NSManagedObject,可解码{
枚举编码键:字符串,编码键{案例库,日期,速率}
@NSManaged公共变量基:字符串
@NSV管理的公共var日期:日期
@NSM管理的公共风险值比率:设置
必需的便利初始化(来自解码器:解码器)抛出{
guard let context=decoder.userInfo[.context]as?NSManagedObjectContext else{fatalError(“错误:没有对象上下文!”)}
让entity=NSEntityDescription.entity(在:context中名为“CurrencyRate”)!
init(实体:实体,插入到:上下文)
let values=try decoder.container(keyedBy:CodingKeys.self)
base=try values.decode(String.self,forKey:.base)
日期=尝试值。解码(date.self,forKey:.date)
let ratesData=try values.decode([String:Double].self,forKey:.rates)
对于ratesData中的(键、值){
let subCurrencyRate=subCurrencyRate(上下文:上下文)
subCurrencyRate.currency=关键字
次货币比率。比率=值
subCurrencyRate.currencyRate=self
}
}
}

要解码JSON,您必须在传递托管对象上下文的扩展中使用
JSONDecoder(上下文:
API),要正确解码
date
,您必须在创建新实体和添加关系时添加适当的
dateDecodingStrategy

,您不需要为此添加特定属性(费率)因为该关系将充当汇率的属性。从建模的角度来看,最好将数据分解为货币对和汇率,然后只需要一个实体。
class CurrencyRate: NSManagedObject, Decodable {
    enum CodingKeys: String, CodingKey { case base, date, rates }

    @NSManaged public var base: String
    @NSManaged public var date: Date
    @NSManaged public var rates: Set<SubCurrencyRate>

    required convenience init(from decoder: Decoder) throws {

        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: No object context!") }
        let entity = NSEntityDescription.entity(forEntityName: "CurrencyRate", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        base = try values.decode(String.self, forKey: .base)
        date = try values.decode(Date.self, forKey: .date)
        let ratesData = try values.decode([String:Double].self, forKey: .rates)
        for (key, value) in ratesData {
            let subCurrencyRate = SubCurrencyRate(context: context)
            subCurrencyRate.currency = key
            subCurrencyRate.rate = value
            subCurrencyRate.currencyRate = self
        }
    }
}