如何在核心数据中使用swift 4 Codable? [英] How to use swift 4 Codable in Core Data?

查看:81
本文介绍了如何在核心数据中使用swift 4 Codable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可编码似乎是一个非常令人兴奋的功能。但是我想知道我们如何在核心数据中使用它?

Codable seems a very exciting feature. But I wonder how we can use it in Core Data? In particular, is it possible to directly encode/decode a JSON from/to a NSManagedObject?

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

I tried a very simple example:

并自己定义 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)

编译器因以下错误而失败:

The compiler failed with this errror:

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

,目标文件是定义 Foo

我想我可能做错了,因为我什至没有通过 NSManagedObjectContext ,但是我不知道该贴在哪里

I guess I probably did it wrong, since I didn't even pass a NSManagedObjectContext, but I have no idea where to stick it.

核心数据是否支持 Codable

推荐答案

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

You can use the Codable interface with CoreData objects to encode and decode data, however it's not as automatic as when used with plain old swift objects. Here's how you can implement JSON Decoding directly with Core Data objects:

首先,使对象实现Codable。此接口必须在对象上定义,而不是在扩展中定义。您也可以在此类中定义编码键。

First, you make your object implement Codable. This interface must be defined on the object, and not in an extension. You can also define your Coding Keys in this class.

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

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

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

Next, you can define the init method. This must also be defined in the class method because the init method is required by the Decodable protocol.

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

用于托管对象的初始化程序是:

However, the proper initializer for use with managed objects is:

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

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

So, the secret here is to use the userInfo dictionary to pass in the proper context object into the initializer. To do this, you'll need to extend the CodingUserInfoKey struct with a new key:

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

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

Now, you can just as the decoder for the context:

required convenience init(from decoder: Decoder) throws {

    guard let context = decoder.userInfo[CodingUserInfoKey.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)
}

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

Now, when you set up the decoding for Managed Objects, you'll need to pass along the proper context object:

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

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

To encode data, you'll need to do something similar using the encode protocol function.

这篇关于如何在核心数据中使用swift 4 Codable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆