在 Swift 中将复杂的 JSON 保存到 Core Data

use*_*163 4 json core-data ios swift

我想将Web服务的JSON结果保存到核心数据,以下是JSON解析的代码。

\n\n
if let jsonResult = try JSONSerialization.jsonObject(with: JSONData!, options: [.mutableContainers]) as? [String: AnyObject]\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我打印 jsonResult,以下是输出

\n\n
["Code": 00, "Desc": success, "iinData": <__NSArrayM 0x1c02531a0>\n{\n  name = \xe2\x80\x9cAAA\xe2\x80\x9d;\n  iin = 123456;\n  isOn = 0;\n},\n{\n  name = "Allahabad Bank";\n  iin = 608112;\n  isOn = 0;\n},\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我可以将Code、Desc插入 Entity1 中,但如何将 innData 插入 Entity2 中。

\n\n

实体 1 结构 实体 2 结构

\n\n

以下是将 JSON 结果插入核心数据的代码

\n\n
func createEntity1From(dictionary: [String: AnyObject]) -> NSManagedObject? {\n    let context = CoreDataStack.sharedInstance.persistentContainer.viewContext\n    if let Entity1 = NSEntityDescription.insertNewObject(forEntityName: \xe2\x80\x9cParamDownload\xe2\x80\x9d, into: context) as? ParamDownload {\n        Entity1.Code= dictionary[\xe2\x80\x9cname\xe2\x80\x9d] as? String\n        Entity1.desc = dictionary[\xe2\x80\x9cdesc\xe2\x80\x9d] as? String\n        return Entity1\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

vad*_*ian 9

将 JSON 直接解码为 Core Data 非常容易Decodable

  • 首先创建 的扩展CodingUserInfoKeyJSONDecoder能够传递托管对象上下文

    extension CodingUserInfoKey {
        static let context = CodingUserInfoKey(rawValue: "context")!
    }
    
    extension JSONDecoder {
        convenience init(context: NSManagedObjectContext) {
            self.init()
            self.userInfo[.context] = context
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • Decodable在两个类中添加一致性

    class Name: NSManagedObject, Decodable {
    
    class ParamDownload: NSManagedObject, Decodable {
    
    Run Code Online (Sandbox Code Playgroud)
  • 在类Name(不是扩展)中添加

    private enum CodingKeys: String, CodingKey { case name, iin, isOn }
    
    required convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }
        let entity = NSEntityDescription.entity(forEntityName: "Name", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        iin = try values.decode(String.self.self, forKey: .iin)
        isOn = try values.decode(Bool.self.self, forKey: .isOn)
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 在类ParamDownload(不是扩展)中添加

    private enum CodingKeys: String, CodingKey { case code = "Code", desc = "Desc", names = "iinData" }
    
    required convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }
        let entity = NSEntityDescription.entity(forEntityName: "ParamDownload", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        code = try values.decode(String.self, forKey: .code)
        desc = try values.decode(String.self, forKey: .desc)
        names = try values.decode(Set<Name>.self, forKey: .names)
        names.forEach { $0.pd = self }
    }
    
    Run Code Online (Sandbox Code Playgroud)

要解码 JSON,请使用便利的初始值设定项创建解码器

let decoder = JSONDecoder(context: CoreDataStack.sharedInstance.persistentContainer.viewContext)
Run Code Online (Sandbox Code Playgroud)

init处理关系。

我建议尽可能多地声明核心数据属性的非可选属性。
如果属性必须保持可选,则替换decodedecodeIfPresent.