iOS (Swift):使用关系获取核心数据
iOS (Swift): Core data fetching with relationships
如果我有一个 Person
实体和一个 Book
实体,其中一个 Person
可以有很多 Book
。
final class Person: NSManagedObject {
@NSManaged public fileprivate(set) var name: String
@NSManaged public fileprivate(set) var books: Set<Book>
}
final class Book: NSManagedObject {
@NSManaged public fileprivate(set) var name: String
@NSManaged public fileprivate(set) var person: Person
static func add(bookNamed name: String, to person: Person) {
guard let context = person.managedObjectContext else { fatalError("Can not obtain managed object Context") }
let book = NSEntityDescription.insertNewObject(forEntityName: "Book", into: context) as Book
book.name = name
book.person = person
}
}
在一些 UIViewController
中,然后我将一些 Book
添加到 Person
:
let alex = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as Person
Alex.name = "Alex"
Book.add("first book", to: alex)
Book.add("second book", to: alex)
Book.add("third book", to: alex)
然后 Book
到另一个 Person
let john = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as Person
john.name = "John"
Book.add("another first book", to: john)
Book.add("another second book", to: john)
然后我重新加载我的应用程序并使用获取请求获取 table 视图中的所有人(即 alex
和 john
)。然后我单击 alex
,这会将我带到另一个视图控制器,它有一个 Person
的实例,我将其指定为 alex
,以便我可以查看与该实例关联的书籍。
问题即使我有1000,Book
是否都加载到内存中?或者,如果我想全部显示它们,是否需要执行另一次提取以获取属于 alex
的 Book
?我只是想弄清楚两个实体之间的关系发生了什么,因为它最近让我有点困惑。
感谢您的帮助。
CoreData
使用代理对象模型。当您执行获取请求时,它会透明地创建所有可直接访问的对象,作为代理。因为它们是代理而不是完整的对象,所以它们实际上并没有在创建时从数据库中加载,而是在需要时(当实际引用属性时)从数据库中加载它们同样,它们可以随时卸载如果它们未经修改且未使用。
在这种情况下,这意味着您的提取请求将为每个 Person
创建卸载的代理。当您在第一个 table 视图中显示人员姓名时,该人员的数据将加载(并缓存)在代理对象中。那时,该人引用的每本书的代理将创建为一个空代理对象。当您随后 select 这本书并显示该书的详细信息时,将从数据库中获取(缓存)实际的图书数据。
注意: 所有这些都非常依赖于实际使用的数据存储,并且仅适用于允许部分加载的存储,例如 sqlite。如果使用 XML 或 plist 存储整个对象图被实例化并加载没有空代理。
如果我有一个 Person
实体和一个 Book
实体,其中一个 Person
可以有很多 Book
。
final class Person: NSManagedObject {
@NSManaged public fileprivate(set) var name: String
@NSManaged public fileprivate(set) var books: Set<Book>
}
final class Book: NSManagedObject {
@NSManaged public fileprivate(set) var name: String
@NSManaged public fileprivate(set) var person: Person
static func add(bookNamed name: String, to person: Person) {
guard let context = person.managedObjectContext else { fatalError("Can not obtain managed object Context") }
let book = NSEntityDescription.insertNewObject(forEntityName: "Book", into: context) as Book
book.name = name
book.person = person
}
}
在一些 UIViewController
中,然后我将一些 Book
添加到 Person
:
let alex = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as Person
Alex.name = "Alex"
Book.add("first book", to: alex)
Book.add("second book", to: alex)
Book.add("third book", to: alex)
然后 Book
到另一个 Person
let john = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as Person
john.name = "John"
Book.add("another first book", to: john)
Book.add("another second book", to: john)
然后我重新加载我的应用程序并使用获取请求获取 table 视图中的所有人(即 alex
和 john
)。然后我单击 alex
,这会将我带到另一个视图控制器,它有一个 Person
的实例,我将其指定为 alex
,以便我可以查看与该实例关联的书籍。
问题即使我有1000,Book
是否都加载到内存中?或者,如果我想全部显示它们,是否需要执行另一次提取以获取属于 alex
的 Book
?我只是想弄清楚两个实体之间的关系发生了什么,因为它最近让我有点困惑。
感谢您的帮助。
CoreData
使用代理对象模型。当您执行获取请求时,它会透明地创建所有可直接访问的对象,作为代理。因为它们是代理而不是完整的对象,所以它们实际上并没有在创建时从数据库中加载,而是在需要时(当实际引用属性时)从数据库中加载它们同样,它们可以随时卸载如果它们未经修改且未使用。
在这种情况下,这意味着您的提取请求将为每个 Person
创建卸载的代理。当您在第一个 table 视图中显示人员姓名时,该人员的数据将加载(并缓存)在代理对象中。那时,该人引用的每本书的代理将创建为一个空代理对象。当您随后 select 这本书并显示该书的详细信息时,将从数据库中获取(缓存)实际的图书数据。
注意: 所有这些都非常依赖于实际使用的数据存储,并且仅适用于允许部分加载的存储,例如 sqlite。如果使用 XML 或 plist 存储整个对象图被实例化并加载没有空代理。