这是以下评论中的后续问题如何映射嵌套的复杂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表。我想显示行程中的乘客,但不需要直接查询乘客的表格。这只是旅行的一个自定义对象/属性。每次我接近乘客都是通过Trips。
那么,有没有一种方法可以让我创建一个名为"TripEntity"的NSManagedObject的新子类,并存储我的乘客——WITH 1。为"Passenger"2创建另一个NSManagedObject子类。在乘客和行程之间建立一种反向关系?简单地说,我只是想让它成为一种属性。从概念上讲,对我来说,这也只是一种属性。这不是真正的关系。。。
还是说,一旦您使用了Core数据,那么每个自定义类型都需要明确地成为NSManagedObject的子类?否则它就不会持久化。我猜这也是对象图的意思。你的图表需要完整。忽略图形之外的任何内容。。。
我之所以这么问,是因为我实际想要存储的JSON对象非常庞大,而且我正在努力减少需要做的工作。
您可以将乘客添加到一个Trip实体中,但由于属性类型受到限制,您必须使用transformable
类型,这对于归档和取消归档对象来说可能非常昂贵。
如果源数据是JSON,最有效的方法是为Passenger
和Trip
创建核心数据实体并添加反向关系。然后使所有的NSManagedObject
类都采用Codable
,并在每个类中添加init(from decoder
和encode(to encoder:
方法。
例如,让我们假设Trip
类与Passenger
有一种多对多的关系,它可能看起来像
@NSManaged public var tripNumber: Int32
@NSManaged public var passengers: Set<Passenger>
并且在CCD_ 10类中存在属性CCD_
@NSManaged public var trip: Trip?
这是CCD_ 13中所需的CCD_。解码器既可以对数组进行解码,也可以对集合进行解码。
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
的扩展,才能在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)
}
采用Codable
的NSManagedObject
类非常适合从JSON数据预填充数据库或进行JSON备份。
任何自定义属性都需要表示为核心数据属性类型之一。这包括字符串和数值等显而易见的东西。它还包括"二进制",它是任何可以转换为NSData
(Swift中的Data
)的东西。
根据你的描述,最好的方法可能是
- 您的
Passenger
类采用NSCoding
- 将
passenger
属性设置为核心数据"可转换"类型。(顺便说一句,这应该是一系列乘客吗?你有一个相关的乘客,但你的问题将其描述为不止一个) - 完成#2之后,将乘客属性的"自定义类"字段设置为类的名称——
Passenger
如果执行这两项操作,Core Data将自动调用NSCoding
方法,在Passenger
类和可以保存在Core Data中的二进制blob之间进行转换。