这是来自以下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
}
}
现在,我决定为我的应用添加持久性。我想有一张行程表。我想显示出行旅客,但不需要表格直接查询旅客。这只是旅行的自定义对象/属性。每次访问旅客时,都是通过Trips。
因此,有一种方法可以创建一个名为'TripEntity'的NSManagedObject新子类并存储我的乘客-无需1.为'Passenger'创建另一个NSManagedObject子类2.创建一个与Passenger和Trip之间成反比关系的关系?简而言之,我只是希望它成为一个属性。从概念上来说,这也只是一个属性。这不是真正的关系...
还是在使用Core-data之后,每个自定义类型都需要显式地成为NSManagedObject的子类?否则,它将不会持续存在。我猜这也是对象 graph 的意思。您的图形需要完整。图外的任何内容都将被忽略...
我之所以这样问,是因为我实际上要存储的JSON对象是巨大的,并且我正在尝试减少需要完成的工作。
答案 0 :(得分:3)
您可以将乘客添加到一个Trip实体中,但是由于属性类型受到限制,您必须使用transformable
类型,这对于归档和取消归档对象可能非常昂贵。
如果源数据是JSON,最有效的方法是为Passenger
和Trip
创建Core Data实体并添加逆关系。然后,使所有NSManagedObject
类都采用Codable
,并向每个类添加init(from decoder
和encode(to encoder:
方法。
例如,假设Trip
类与Passenger
有很多关系,
@NSManaged public var tripNumber: Int32
@NSManaged public var passengers: Set<Passenger>
并且在Passenger
类中有一个属性trip
@NSManaged public var trip: Trip?
这是Decodable
中必需的Trip
初始化程序。解码器可以解码数组和集合。
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
。
相应的编码器非常简单-
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备份。
答案 1 :(得分:1)
任何自定义属性都必须可以表示为“核心数据”属性类型之一。其中包括显而易见的东西,例如字符串和数值。它还包含“二进制”,即可以与NSData
(在Swift中为Data
)之间进行转换的任何东西。
根据您的描述,最好的方法可能是
NSCoding
课程采用Passenger
。passenger
属性成为Core Data“可转换”类型。 (顺便说一句,这应该是一排乘客吗?您有一个相关的乘客,但是您的问题描述的是好像有一个以上的乘客)。Passenger
。如果您做这两件事,Core Data将自动调用NSCoding
方法,以在您的Passenger
类和可以保存在Core Data中的二进制Blob之间进行转换。