这是苹果官方文档 Core Data Programming Guide 的渣翻译。
很多的CoreData功能依赖于你创建的一个数据库对象集合(Schema),这个集合用来描述应用中的实体(Entity)、字段、和它们之间的关系。CoreData使用一个NSManagedObjectModel的实例作为Schema。一般来说,这个模型越丰富,CoreData越能更好地支持你的应用。
一个对象模型(managed object model)让CoreData可以从持久化存储中匹配一个你在应用中使用的记录,并转化为数据(managed object)。这个模型是一个表(Entity Description)的集合(NSEntityDescription的实例)。一个Entity Description描述了一个Entity(你可以想象成一个在数据库里面的表)明确的名称、在应用中用来表示这个Entity的类和拥有的属性(字段和关系)。
创建一个Entity和设置它的属性
创建一个新的项目并打开模板选择对话框的时候,勾选使用CoreData的选项。一个CoreData模型文件作为这个模板的一部分将会被自动创建。这个源文件后缀为.xxcdatamodeld。打开这个文件可以看到CoreData模型编辑器。
创建一个Entity
- 点击“Add Entity”。
一个新的未命名Entity会出现在导航栏Entity列表中。 - 选择这个新的未命名Entity。
- 输入名称并回车。
为这个Entity创建属性和关系
- 当这个Entity被选中的时候,在相应的编辑框点击底部的加号(+)。
一个新的未命名属性或者关系(其实也是一个属性)为被自动添加在属性或者关系编辑器上。 - 选择新的未命名属性。
这个属性配置会显示在数据模型指示框上。 - 给这个属性设置一个名称并回车。
这个属性或关系的信息会显示在编辑区域。
图2-1表示有一个叫Employee的Entity,并有以下属性来描述这个Entity:出生日期、名字、入职日期。
图2-1 Xcode数据模型表及其中的Employee Entity
这时候你已经创建了一个Entity,但是你还没有任何数据。数据会在启动应用之后创建。在应用内,这些Entity被被用来创建托管对象(NSManagedObject实例)。
配置一个Entity
现在你已经为一个Entity命了名,你可以在数据模型配置器中进步一配置这个Entity。
图2-2 在数据模型配置器中的Entity选项
Entity名称和类名
要注意Entity名和类名(一个NSManagedObject的子类)并不是一样的。数据模型中的Entity结构并不需要跟类层次结构相匹配。图2-2表示了一个使用了Objective-C类命名模式的的类名,带有一个MO后缀。Entity名和类名是强制要求的。
抽象Entity
如果你不想创建任何Entity实例你可以指定一个Entity为抽象的。典型的,如果你有几个Entity,这些Entity均表示(继承自)同一个公共、不需要自己实例化Entity,你可以让此公共Entity变成抽象的。例如,在Employee Entity中你可以定义一个Person作为一个抽象Entity,这样就只能实例化子Entity(Employee和Customer)。在数据模型配置框的Entity框配置了一个抽象Entity之后,你就告诉了CoreData这个Entity永远不会被实例化。
Entity继承
Entity的继承类似于类的继承,同样十分有用。如果你有许多相似的Entity,你可以提取相同的属性到超Entity(Super Entity)中,就是父Entity(Parent Entity)。相比起在几个Entity中同时制定相同的属性,你可以在一个Entity中定义一遍,子Entity就能继承它们。例如,你可以定义一个 "Person" Entity,拥有叫“firstName”和“lastName”的属性,和它的子Entity “Employee”和“Customer”,继承了以上属性。图2-3阐述了这个例子。可以在右下角转换编辑器类型之后显示Entity的图表结构。
在很多时候,你可以实现一个代表父Entity的自定义类。比起在多个类中实现多次类似的业务逻辑,你可以在一个类中完成即可。
注意
在使用SQLite数据库的时候要十分小心地使用Entity继承。所有继承自一个Entity的Entity数据都会存在同一个表。这个SQLite的特性会导致性能问题。
图2-3 Entity继承图
定义字段和关系
一个Entity的属性就是它的字段和关系,包括了继承来的属性(如果有的话)。除了别的特性之外,每个属性都有一个名字和类型。一个属性名字不能是任何NSObject、NSManagedObject的无参数方法名。例如,你不能给一个属性命名为“description”(详见NSPropertyDescription)。
临时字段(Transient Attribute)是一个你在模型中定义了,但是不会保存到数据库中的属性。CoreData也会跟踪更新临时字段,所以它们会被保存用来做撤销(undo)操作。临时字段有很多用法,包括保存计算值和结果值。
注意
如果你撤销了一个临时字段的更新操作,CoreData不会调用setter方法来恢复旧值 —— 它会直接使用之前临时保存的值。
图2-4 数据模型配置器中的字段框
字段
在CoreData模型编辑器和CoreData模型配置器中可以配置一个字段。CoreData原生支持多种字段类型,例如string、date和integer(表示NSString、NSDate和NSNumber的实例)。
你可以指定一个字段是可选的,这样就表示这个字段不是非空的。然而一般来说,不提倡这样做,特别是数字类型的。更好的做法是,你也可以给强制字段设置一个默认值——在字段中设置——0.这是因为在SQLite中,NULL的匹配和值对比不同于Objective-C的nil。NULL在数据库中不同于0,用0搜索是不能匹配到列为NULL的数据的。更进一步,NULL在数据库中不等同于空字符串或者空数据。
关系(Relationsthip)和Fetched属性(Fetched Property)
在CoreData模型编辑器中可以定义一个关系,在数据模型配置器中可以指定这个关系的值。
图2-5 数据模型配置器中的关系
CoreData支持一对一和一对多的关系和Fetched属性。Fetched属性表示弱引用(weak)、单指向(one-way)关系。在employee和department中,department的fetched属性可以是“recent hires”(employee中没有这个“recent hires”的关系反转映射)。
关系类型域中定义了这个关系是一个一对一还是一对多关系。关系是单向定义。如果是定义一对多关系,你需要定义创建两个一对多关系,并且设置它们为相互反向关系。
目标域(Destination field)定义了哪个对象或者对象集合在代码中会被访问。如果这个关系定义为了一个一对一关系,会返回一个对象(或者nil,如果这个关系是可选的)。如果这个关系定为了一个一对多关系,那么会返回一个set(或者nil)。
反向域(Inverse field)定义了关系的另一半范畴。因为每一个关系设置都是单向的,所以这个域会绑定两个互相指向的关系。
更多关于关系的细节可以参照 Creating Managed Object Relationships。
网友评论