正如前面所讨论的,托管对象的NSManagedObject实例类,或者NSManagedObject的子类,表示着Entity的实例。NSManagedObject是一个泛型类,这个泛型类实现了所有托管对象(managed object)的基本行为。及可以创建自定义的NSManagedObject 的子类,虽然这不是必要的。如果你不需要对Entity自定义任何逻辑,那么就没有必要为这个Entity创建一个自定义的类。你可以为一下原因自定义类,例如:提供自定义的访问或验证方法,使用非标准的属性,指定相关的密匙,计算得出值,执行其他自定义的逻辑。
创建自定义的托管对象子类(Creating Custom Managed Object Subblasses)
在Objective-C的托管对象子类里,你可以模拟属性(attributes)在接口文件中生命属性(properties),但是你不用声明实例变量。
@interface MyManagedObject : NSManagedObject
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSDate *date;
@end
注意,属性(property)必须声明为nonatomic和strong的。处于性能的原因,Core Data通常不会复制(copy)对象的值,即便对象遵循NSCopying协议。
在Objective-C的实现文件中,还必须要指定属性的动态(给property添加一个@dynamic)
@implementation MyManagedObject
@dynamic title;
@dynamic date;
@end
在Swift中,声明属性使用@NSManaged关键词
class MyManagedObject: NSManagedObject {
@NSManaged var title: String?
@NSManaged var date: NSDate?
}
Core Data动态生成有效、公共的管理entity的方法,这些方法包括set、get的属性和关系方法。因此,你通常不用编写自定义的建模属性访问器方法。
重写方法指南(Gudelines for Overriding Methods)
NSManagedObject本身就有很多NSObject的特征,这些特征以便于托管对象(managed objects)可以正确的集成到Core Data的基本方法,
Core Data 依赖与NSManagedObject的下列方法实施,你不应该忽略:
- primitiveValueForKey:
- setPrimitiveValue:forKey:
- isEqual:
- hash
- superclass
- class
- self
- zone
- isProxy
- isKindOfClass:
- isMemberOfClass:
- conformsToProtocol:
- respondsToSelector:
- managedObjectContext
- entity
- objectID
- isInserted
- isUpdated
- isDeleted
- isFault
在重写(overriding)initWithEntity:insertIntoManagedObjectContext:的方法时遇到阻碍(种类或者类型方面的)。如果在调试(debugging)期间类型缺失或者出错,则结果是不可预知的。通常的可能是没有重写键值编码的方法,例如 valueForKey:、setValue:forKeyPath。
此外,在重写awakeFromInsert,awakeFromFetch,和validateForUpdate:的验证方法前,请求他们父类时(superclass implementaion)要小心,在重写储存器的方法时你可能会对性能产生一些负面影响。
定义属性和数据储存(Defining Properties and Data Storage)
在某些方面,一个托管对象(managed object)就像一个字典一样(dictionary)。它就像一个通用的储存容器一样,有效的提供和储存那些通过NSEntityDescription对象定义的属性。NSManagedObject支持一系列的属性值,常见类型包括:字符串、日期、和数字类型(详情可以参阅NSAttributeDescription)因此,你不必在子类中定义实现变量。但是,如果需要执行非常标准的属性或者保存时区是,你可能要这么做。此外,当你使用了较大的二进制数据时,在你的子类中需要考虑下性能的问题。
使用非标准属性(Using Nonstandard Attributes)
在默认情况下,NSManagedObject储存属性使用的都为内部结构,并且一般情况下Core Data在自己管理的类型(结构)下工作要比自定义的实例类型下工作更为有效。
有时候需要使用不能直接支持的类型,例如,在一个图形应用程序,可能像定义一个具有颜色和范围的实体矩形,也就是NSColor和NSRect的实例。这种情况下就要根据需要创建自己所需的NSManagedObject子类了。
日期,时间和保存时区(Dates, Times, and Preserving Time Zones)
NSManagedObject用NSDate对象来表示日期,储存的时间内部通过基于GMT得到的NSTimeInterval值。因为时区是不确定的--Core Data一般用GMT时间代表日期,这样在数据库中找寻到的时间是标准化的。如果需要保存时区信息,你可以创建一个NSManagedObject的子类来保存。
自定义初始化和释放(Customizing Initialization and Deallocation)
Core Data控制托管对象(managed object)的生命周期。除了断层和撤销,你不能够像处理对待其他标准Objective-C的NSObject类的对象那样进行实例化,破获,和重建。
当托管对象(managed Object)被创键,它将在托管对象的模型(managed object model)中根据它的实体(Entity)得到的默认值进行初始化。在许多的情况下模型中设置的默认值是足够的,有事,可能会使用到模型中不能表示的动态值来执行额外的初始化。
在一个典型的Objective-C的类中,通常重写指定的初始化方法(一般是init方法)。在NSManagedObject的子类中,有三种不同的方法你可以用作重写:initWithEntity:insertIntoManagedObejctContext;, awakeFromInsert, awakeFromFetch。不要重写init方法。建议不要重写initWithEntity:insertIntoManagedObjectContext的方法,重写这个方法造成的状态变化可能会不能正确的结合撤销和重做(undo and redo)。其他 的两种方法,awakeFromInsert和awakeFromFetch用于区分不同的环境。
- awakeFromInsert在对象(Object)创建时第一个被创建,并且在对象的生命周期中只能调用一次。
awaakeFromInsert调用之后立即调用initWithEntity:insertIntoManagedObjectContext:或者insertNewObjectForEntityForName:inManagedObjectContext:。可以用awakeFromInsert初始化特殊的属性值,例如对象的时间,如下所示。
Objective-C
- (void)awakeFromInsert
{
[super awakeFromInsert];
[self setCreationDate:[NSDate date]];
}
Swift
override func awakeFromInsert() {
super.awakeFromInsert()
creationDate = NSDate()
}
- 当对象从持久化储存中初始化时awakeFromFetch被调用(当获取到值的时候)。
你可以重写awakeFromFetch,例如创建临时值和其他缓存时。改变处理(change processing)是awakeFormFetch明确禁止的,这样你可以方便使用公共的set访问器而不弄脏(dirtying)对象(Object)或者它的上下文(context)。这中禁止意味着无论如何你都不要对关系进行操作,因为所做的更改将不会正确的传播到目标对象。而更重要的是awakeFromFetch,你可以重写awakeFromFecth或者使用任何运行循环(run loop-related)相关的方法,例如:performSelector:withObject:afterDelay:。
避免重写dealloc时清除临时属性和其他变量,可以重写didTurnIntoFault。当一个对象报错时Core Data会立即自动调用didTurnintoFault的方法变并且立即释放。你可以有效的减少一些托管对象(managed object)错误的内存开支,对于正确的执行清除操作这很重要。
Xcode生成的子类(Xcode Generated Subclasses)
从Xcode8,ios10,macOS10.12开始,Xcode可以自动从Core Data中生成NSManagedObject的子类或者延展(extensions)或者类别(categories)
要在现有的项目中启动此功能,首先要确保数据模型配置正确:
1.选中Core Data的模型文件(Model file),并且打开文件检查程序(open the File inspector)
2.确认工具版本设置Xcode 8或者更高的版本。
3.确认代码生成设置为当前正在使用的语言。
再配置了数据模型之后,可以配置每个实体(Entity):
1.选中要配置的实体(Entity)
2.打开数据模型检查器
3.将代码生成器设置为否(None)、类定义(Class Defintion)或者类别/延展(Category/Extension)
在数据模型配置之后,Xcode再生成子类、类别/延展时,相关的实体(Entity)会根据数据模型中的配置生成。
注:
生成的源代码并不包含在项目中(project)中,并打算成为生成过程的一部分。你将无法在项目源列表中查看文件,但是可以在生成目录中查看这些文件。这些文件被经常再生,所以没有手动编辑他们的价值。
如果你希望你的NSManagedObject类添加额外的便利方法或者业务逻辑,你可以创建一个类(Objective-C中)或者延展(swift中),在其中实现方法或者逻辑。