核心数据中具有自定义类型的所有属性都必须是关系吗?
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
)。
根据您的描述,最好的方法可能是
- 为您的
Passenger
class 采用 NSCoding
。
- 使
passenger
属性 成为核心数据 "transformable" 类型。 (顺便说一句,这应该是一组乘客吗?你有一个相关的乘客,但你的问题描述的好像不止一个)。
- 完成#2 后,将乘客 属性 的 "custom class" 字段设置为您的 class--
Passenger
.
如果你做了这两件事,Core Data 会自动调用 NSCoding
方法在你的 Passenger
class 和可以保存在 Core Data 中的二进制 blob 之间进行转换。
您可以将乘客添加到一个旅行实体,但由于属性类型受到限制,您必须使用 transformable
类型,归档和取消归档对象可能非常昂贵。
如果源数据是 JSON,最有效的方法是为 Passenger
和 Trip
创建核心数据实体并添加反向关系。然后让所有的NSManagedObject
classes都采用Codable
并且给每个class.
添加init(from decoder
和encode(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 备份。
这是来自以下评论的后续问题 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
)。
根据您的描述,最好的方法可能是
- 为您的
Passenger
class 采用NSCoding
。 - 使
passenger
属性 成为核心数据 "transformable" 类型。 (顺便说一句,这应该是一组乘客吗?你有一个相关的乘客,但你的问题描述的好像不止一个)。 - 完成#2 后,将乘客 属性 的 "custom class" 字段设置为您的 class--
Passenger
.
如果你做了这两件事,Core Data 会自动调用 NSCoding
方法在你的 Passenger
class 和可以保存在 Core Data 中的二进制 blob 之间进行转换。
您可以将乘客添加到一个旅行实体,但由于属性类型受到限制,您必须使用 transformable
类型,归档和取消归档对象可能非常昂贵。
如果源数据是 JSON,最有效的方法是为 Passenger
和 Trip
创建核心数据实体并添加反向关系。然后让所有的NSManagedObject
classes都采用Codable
并且给每个class.
init(from decoder
和encode(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 备份。