核心数据 – 如何在核心数据中使用swift 4 Codable?

Codable似乎是一个非常令人兴奋的功能。但我想知道如何在核心数据中使用它?特别是,是否可以直接从/向NSManagedObject编码/解码JSON?

我尝试了一个非常简单的例子:

并自己定义了Foo:

import CoreData

@objc(Foo)
public class Foo: NSManagedObject,Codable {}

但是当像这样使用它时:

let json = """
{
    "name": "foo","bars": [{
        "name": "bar1",}],[{
        "name": "bar2"
    }]
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let foo = try! decoder.decode(Foo.self,from: json)
print(foo)

编译器因此错误而失败:

super.init isn't called on all paths before returning from initializer

目标文件是定义Foo的文件

我想我可能做错了,因为我甚至没有传递NSManagedObjectContext,但我不知道在哪里坚持它。

Core Data是否支持Codable?

您可以将Codable接口与CoreData对象一起使用来对数据进行编码和解码,但是它不像使用普通的旧swift对象那样自动化。以下是如何使用Core Data对象直接实现JSON解码:

首先,使对象实现Codable。必须在对象上定义此接口,而不是在扩展中定义。您还可以在此课程中定义编码密钥。

class MyManagedObject: NSManagedObject,Codable {
    @NSManaged var property: String?

    enum CodingKeys: String,CodingKey {
       case property = "json_key"
    }
}

接下来,您可以定义init方法。这也必须在类方法中定义,因为Decodable协议需要init方法。

required convenience init(from decoder: Decoder) throws {
}

但是,与托管对象一起使用的正确初始化程序是:

NSManagedObject.init(entity: NSEntityDescription,into context: NSManagedObjectContext)

所以,这里的秘密是使用userInfo字典将适当的上下文对象传递给初始化器。为此,您需要使用新密钥扩展CodingUserInfoKey结构:

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

现在,您可以作为上下文的解码器:

required convenience init(from decoder: Decoder) throws {

    guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError() }
    guard let entity = NSEntityDescription.entity(forEntityName: "MyManagedObject",in: context) else { fatalError() }

    self.init(entity: entity,in: context)

    let container = decoder.container(keyedBy: CodingKeys.self)
    self.property = container.decodeIfPresent(String.self,forKey: .property)
}

现在,当您为托管对象设置解码时,您需要传递正确的上下文对象:

let data = //raw json data in Data object
let context = persistentContainer.newBackgroundContext()
let decoder = JSONDecoder()
decoder.userInfo[.context] = context

_ = try decoder.decode(MyManagedObject.self,from: data) //we'll get the value from another context using a fetch request later...

try context.save() //make sure to save your data once decoding is complete

要编码数据,您需要使用编码协议功能执行类似操作。

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...