1.5 创建和修改自定义Managed Object(Core Data Programming Guide翻译)

这是苹果官方文档 Core Data Programming Guide 的渣翻译。

正如之前讨论的,managed object是累NSManagedObject的实例,或者NSManagedObject的子类的实例,它代表了一个Entity的实例。NSManagedObject是一个的、实现了所有managed object基本需求行为的类。你可以创建NSManagedObject的自定义子类,虽然这并不是常需要的。对于一个Entity,如果你不需要任何自定义的逻辑,你不必要为这个Entity创建一个自定义类。在某些时候,你可能需要实现一个自定义类,例如,为了提供一个自定义访问或者验证方法、使用不标准的字段、指定依赖的键、计算结果值、实现一些其他的自定义逻辑。

创建自定义Managed Object子类

在一个Objective-C managed object子类中,你可以在声明文件中声明模型化字段对应的属性,但是你不能声明实例变量。

@interface MyManagedObject : NSManagedObject
 
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSDate *date;
 
@end

注意那些属性被声明为nonatomic何strong。为了性能,Core Data不会复制对象值,甚至虽然这个值的类遵循了NSCopying protocal。

在Objective-C实现文件中,你需要修饰属性为dynamic:

@implementation MyManagedObject
@dynamic title;
@dynamic date;
@end

在Swift中,你需要声明这些属性使用了@NSManaged关键字:

class MyManagedObject: NSManagedObject {
    @NSManaged var title: String?
    @NSManaged var date: NSDate?
}

Core Data会根据这个managed object的Entity对应的数据模型,动态生成每个属性的高效的公共、私有的gett和setter访问方法、关系访问方法。

覆写方法指南

NSManagedObject它本身自定义了许多NSObject的特性,所以managed object可以很好地集成到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

不提倡覆写 initWithEntity:insertIntoManagedObjectContext:和description方法。如果在debug过程中description被置为fault,可能会导致不可预知的结果。你还应该不要覆写那些KVC方法,例如valueForKey: 和 setValue:forKeyPath:。

另外,在覆写awakeFromInsert、awakeFromFetch和验证方法例如validateForUpdate:之前,先调用父类的实现方法。对于覆写访问方法要十分小心,因为你可能会令性能受到不好的影响。

定义属性和数据存储

在某些方面,一个managed object操作起来就像一个字典——它是一个常见的容器对象,并且提供了NSEntityDescription对象绑定的属性的高效存储功能。NSManagedObject支持特定范围内的一些公共类型的字段值,包括string、date和number(更多细节请看NSAttributeDescription)。因此,你不需要在子类中定义实例变量。然而,如果你需要实现非标准的字段或者时区,你可能就需要。另外,如果你使用大型的二进制数据对象,可能会存在性能降低的问题——参考Binary Large Data Objects (BLOBs)

使用非标准字段

在默认情况下,NSManagedObject在内部结构中把属性作为对象存储,通常来讲使用Core Data自己控制的存储方式比自定义实例变量要高效。

有些时候你可能需要使用一些不能直接支持的类型,例如color和C结构体。例如,在一个画图应用中你可能想要定义一个矩形Entity,这个Entity拥有一个color字段和一个bounds字段,这里color是NSColor的实例,bounds是NSRect的结构体。在这种情况下,你需要创建一个NSManagedObject的子类。

日期、时间和时区

NSManagedObject使用NSDate对象表示日期字段,内部使用基于格林尼治时间(GMT)的NSTimeInterval值存储时间值。不同时区的时间不是精确区分存储的——一般你应该使用一个基于GMT的Core Data日期来表示,这样在数据库内搜索才能统一标准化。如果你需要根据实际时区操作数据,你需要在数据模型中存储一个时区字段,这样你就需要创建一个NSManagedObject子类。

自定义初始化和释放

Core Data控制着managed object的生命周期。你不能用一个标准的Objective-C对象的理解,来假设一个managed object的生命周期——managed object会被框架在需要的时候实例化、销毁和唤醒。

当一个managed object被创建,会使用它所属的模型对象中的Entity的默认值来初始化。在许多情况下,在数据模型中配置的默认值是齐全的。然而,你可能希望做一些额外的初始化操作——可能使用dynamic值(例如现在的日期和时间)不能在模型中表现出来。

在一个标准的Objective-C类中,你通常覆写指定的初始化器(一般是init方法)。在一个NSManagedObject子类中,有3个不同的方法你可以用来自定义初始化——覆写initWithEntity:insertIntoManagedObjectContext:、awakeFromInsert 或 awakeFromFetch。不要覆写init。不提倡你覆写initWithEntity:insertIntoManagedObjectContext:,因为在这个方法中的状态改变可能不能很好地集成撤销和重做。另外两个方法, awakeFromInsert 和 awakeFromFetch,在以下两种不同的情况中可以区分开来:

  • awakeFromInsert在一个对象声明周期内只会被调用一次——第一次创建的时候。
    awakeFromInsert在你调用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用以创建临时值和其他缓存。修改处理在此过程不可用,所以你可以很方便地使用公共的setter访问方法,而不用造成MOC中对象数据的混乱。然而,修改处理不可用表示,你不应该篡改关系,不然修改就不能正确地传递到目标对象上。为了替代覆写awakeFromFetch,你可以覆写awakeFromInsert或采用一些run loop相关的方法,例如performSelector:withObject:afterDelay:。

为了避免dealloc清除掉临时属性和其他变量,当一个对象转变为fault但是并未完全释放之前,覆写的didTurnIntoFault. didTurnIntoFault会被Core Data自动调用。你可以提前转变一个对象为fault,以降低内存消耗(详见Reducing Memory
Overhead
),所以确保你在didTurnIntoFault中执行了清理操作是非常重要的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 这是苹果官方文档 Core Data Programming Guide 的渣翻译。 Core Data名词解释 ...
    西蒙SIMON阅读 1,144评论 1 51
  • 虽然从接触iOS开发开始,做的每一个项目都在用Core Data,但是一些比较底层的东西都是boss写的或者用的是...
    卖萌凉阅读 2,800评论 1 11
  • 适读对象: 需要入门Core Data的朋友; 像我一样,尚未学过数据库相关课程,不太懂怎么写SQLite语句的朋...
    AntonyWong阅读 5,042评论 8 21
  • 收到王伟的微信,是在早起上班的路上。今天是周六,本来是不上班的,但是因着清明的调休,又要上班了。 地铁上人很多,菁...
    妙所阅读 767评论 5 11
  • 外出,随处可见,“请走人行道”、“请勿乱仍垃圾”、“请勿践踏花草”等等标语。别说国内,一次看外国新闻,竟然看到一处...
    峥嵘奇峰阅读 368评论 0 1