1

这是以下评论中的后续问题如何映射嵌套的复杂 JSON 对象并将它们保存到核心数据?.

想象一下,我的应用程序已经有了这个代码。

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
    }
}

现在我决定为我的应用程序添加持久性。我只想一张旅行表。我想显示旅行下的乘客,但不需要表格来直接查询乘客。它只是旅行的自定义对象/属性。每次我访问乘客时,都会通过 Trips。

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

或者,一旦您使用 Core-data,那么每个自定义类型都需要明确地成为 NSManagedObject 的子类?否则不会持久化。我猜这也是对象的含义。你的图表需要是完整的。图表之外的任何内容都将被忽略...

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

4

2 回答 2

4

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

如果源数据是 JSON,最有效的方法是创建 Core Data 实体PassengerTrip添加反向关系。然后让所有的NSManagedObject类都采用Codable并为每个类添加init(from decoderencode(to encoder:方法。

例如,让我们假设Trip该类与它有一对多关系Passenger可能看起来像

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

Passenger类中有一个属性trip

@NSManaged public var trip: Trip?

DecodableTrip. 解码器可以解码数组和集合。

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{ $0.trip = self }
}

反向关系通过forEach线设置。
您必须添加扩展名JSONDecoder才能传递对象NSManagedObjectContext中的电流userInfo

对应的编码器——非常简单——</p>

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采用的类Codable非常适合从 JSON 数据预填充数据库或进行 JSON 备份。

于 2018-12-31T17:51:53.877 回答
1

任何自定义属性都必须是可以表示为核心数据属性类型之一的东西。这包括明显的东西,如字符串和数值。它还包括“二进制”,这是可以转换为/从NSDataData在 Swift 中)的任何内容。

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

  1. NSCoding为您的Passenger班级采用。
  2. 使passenger属性成为核心数据“可转换”类型。(顺便说一句,这应该是一组乘客吗?您有一个相关的乘客,但您的问题将其描述为好像不止一个)。
  3. 执行 #2 后,将乘客属性的“自定义类”字段设置为您的类的名称-- Passenger

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

于 2018-12-31T17:34:53.710 回答