核心数据中具有自定义类型的所有属性都必须是关系吗?

Do all attributes with a custom type in core-data have to be a relationship?

这是来自以下评论的后续问题 How to map nested complex JSON objects and save them to core data?

假设我已经为我的应用程序准备了这段代码。

class Passenger{
    var name: String
    var number: String
    var image : UIImage
    // init method
}
class Trip {
    let tripNumber : Int
    let passenger : Passenger

    init(tripNumber: Int, passenger: Passenger) {
        self.tripNumber = tripNumber
        self.passenger = passenger
    }
}

现在我决定为我的应用程序添加持久性。我只是 想要 有一个 table 的旅行。我想显示行程中的乘客,但不需要 table 直接查询乘客。这只是一次旅行的习惯object/property。每次我访问 passenger 都是通过 Trips。

那么有没有一种方法可以创建一个名为 'TripEntity' 的 NSManagedObject 的新子类并存储我的乘客 — 无需 1. 为 'Passenger' 创建另一个 NSManagedObject 子类 2. 创建与乘客和旅行之间的反比关系?简单地说,我只是希望它成为一个属性。从概念上讲,对我来说它也只是一个属性。这不是真正的关系...

或者一旦您使用核心数据,那么每个自定义类型都需要显式成为 NSManagedObject 的子类?否则它不会被持久化。我猜这也是 object graph 的意思。您的图表需要完整。图表之外的任何内容都将被忽略...

我问这个是因为我实际想要存储的 JSON 对象是巨大的,我正试图减少需要完成的工作。

任何自定义 属性 都需要能够表示为核心数据 属性 类型之一。这包括明显的东西,如字符串和数值。它还包括"binary",这是可以转换的任何东西to/from NSData(Swift中的Data)。

根据您的描述,最好的方法可能是

  1. 为您的 Passenger class 采用 NSCoding
  2. 使 passenger 属性 成为核心数据 "transformable" 类型。 (顺便说一句,这应该是一组乘客吗?你有一个相关的乘客,但你的问题描述的好像不止一个)。
  3. 完成#2 后,将乘客 属性 的 "custom class" 字段设置为您的 class-- Passenger.

如果你做了这两件事,Core Data 会自动调用 NSCoding 方法在你的 Passenger class 和可以保存在 Core Data 中的二进制 blob 之间进行转换。

您可以将乘客添加到一个旅行实体,但由于属性类型受到限制,您必须使用 transformable 类型,归档和取消归档对象可能非常昂贵。

如果源数据是 JSON,最有效的方法是为 PassengerTrip 创建核心数据实体并添加反向关系。然后让所有的NSManagedObject classes都采用Codable并且给每个class.

添加init(from decoderencode(to encoder:方法

例如,假设 Trip class 与 Passenger 之间存在一对多关系,它可能看起来像

@NSManaged public var tripNumber: Int32
@NSManaged public var passengers: Set<Passenger>

并且在 Passenger class 中有一个属性 trip

@NSManaged public var trip: Trip?

这是 Trip 中必需的 Decodable 初始值设定项。解码器可以解码数组和集合。

private enum CodingKeys: String, CodingKey { case tripNumber, passengers }

public required convenience init(from decoder: Decoder) throws {
    guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Context Error") }
    let entity = NSEntityDescription.entity(forEntityName: "Trip", in: context)!
    self.init(entity: entity, insertInto: context)
    let values = try decoder.container(keyedBy: CodingKeys.self)
    tripNumber = try values.decode(Int32.self, forKey: .tripNumber)
    passengers = try values.decode(Set<Passenger>.self, forKey: .passengers)
    passengers.forEach{ [=12=].trip = self }
}

反向关系通过forEach行设置。
您必须添加 JSONDecoder 的扩展才能在 userInfo 对象中传递当前的 NSManagedObjectContext

相应的编码器是 – 非常简单 –

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(tripNumber, forKey: .tripNumber)
    try container.encode(passengers, forKey: .passengers)
}

NSManagedObject classes 采用 Codable 非常适合从 JSON 数据预填充数据库或进行 JSON 备份。