ios - 在 Swift 中将复杂的 JSON 保存到 Core Data
问题描述
我想将 Web 服务的 JSON 结果保存到核心数据,以下是 JSON 解析的代码。
if let jsonResult = try JSONSerialization.jsonObject(with: JSONData!, options: [.mutableContainers]) as? [String: AnyObject]
如果我打印 jsonResult,以下是输出
["Code": 00, "Desc": success, "iinData": <__NSArrayM 0x1c02531a0>
{
name = “AAA”;
iin = 123456;
isOn = 0;
},
{
name = "Allahabad Bank";
iin = 608112;
isOn = 0;
},
)
我可以将Code, Desc插入到 Entity1 中,但是如何将 innData 插入到 Entity2 中。
以下是将 JSON 结果插入核心数据的代码
func createEntity1From(dictionary: [String: AnyObject]) -> NSManagedObject? {
let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
if let Entity1 = NSEntityDescription.insertNewObject(forEntityName: “ParamDownload”, into: context) as? ParamDownload {
Entity1.Code= dictionary[“name”] as? String
Entity1.desc = dictionary[“desc”] as? String
return Entity1
}
}
解决方案
将 JSON 直接解码为 Core Data 非常容易Decodable
首先创建扩展
CodingUserInfoKey
并JSONDecoder
能够传递托管对象上下文extension CodingUserInfoKey { static let context = CodingUserInfoKey(rawValue: "context")! } extension JSONDecoder { convenience init(context: NSManagedObjectContext) { self.init() self.userInfo[.context] = context } }
Decodable
在两个类中添加一致性class Name: NSManagedObject, Decodable { class ParamDownload: NSManagedObject, Decodable {
在类
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) }
在类
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 } }
要解码 JSON,请使用便利初始化程序创建解码器
let decoder = JSONDecoder(context: CoreDataStack.sharedInstance.persistentContainer.viewContext)
方法处理init
关系。
我建议尽可能多地声明 Core Data 属性是非可选的。
如果一个属性必须是可选decode
的,用decodeIfPresent
.
推荐阅读
- java - 如何为使用未知参数调用另一个方法的方法编写 Mockito 测试?
- c++ - 多管道,C++
- c++ - “struct seq<0, 1, 2>{}”数据类型是什么意思?
- alfresco - Alfresco - 将收件人姓名添加到工作流通知电子邮件模板
- python - 与 eval() 相对的 Python
- rest - 如果资源正在使用且无法删除,请更正 Delete API 的 HTTP 响应代码
- c# - 如果继承,实体框架返回错误的对象类型
- flutter - 我正在尝试将动态 url 加载为初始 url bt 它没有加载到 webview 中。如果我将 url 放入 tem var 并将 temp 用作初始 url,那么它将起作用
- javascript - Javascript Strigify Push 和 Shift 给了我错误
- python - 用python将所有浮点数乘以一个数字