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

标签 swift core-data swift4 xcode9 codable

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

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

enter image description here

并自己定义了 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 接口(interface)与 CoreData 对象一起使用来编码和解码数据,但是它不像与普通的旧 swift 对象一起使用时那样自动。以下是如何直接使用 Core Data 对象实现 JSON 解码:

首先,让您的对象实现 Codable。此接口(interface)必须在对象上定义,而不是在扩展中定义。您还可以在此类中定义您的编码键。

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

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

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

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

但是,用于托管对象的正确初始化程序是:

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

所以,这里的秘诀是使用 userInfo 字典将正确的上下文对象传递到初始化程序中。为此,您需要使用新 key 扩展 CodingUserInfoKey 结构:

extension CodingUserInfoKey {
   static let context = CodingUserInfoKey(rawValue: "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)
}

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

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

要对数据进行编码,您需要使用编码 协议(protocol)函数执行类似的操作。

关于swift - 如何在核心数据中使用 swift 4 Codable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51504410/

相关文章:

ios - '初始化(contentsOfURL :)' is unavailable: APIs deprecated as of iOS 7 and earlier are unavailable in Swift

ios - 如何在后台创建多个对象?

ios - 如何使用 Swift 附加 CoreData 对象?

swift - 不符合 Decodable/Codable 协议(protocol)

Swift4/JSON/解码

ios - 未调用 AVCaptureMetadataOutputObjectsDelegate 方法

SwiftUI Picker 不显示选项

ios - 使用动画快速更改圆形边框颜色

swift - 快速更改桌面 View 滑动按钮图像图标颜色

ios - 如何向数据模型文件创建的 NSManagedObject 子类添加属性?