Upload
lora-newton
View
325
Download
0
Embed Size (px)
Citation preview
Core Data 简介• Core Data 是 Cocoa 里面一套非常受欢迎的
框架,从 Mac OS X 10.4 提供以来,在 10.5 中引入了完善的 schema 迁移机制,再到 iPhone OS 3.0 时被引入 Cocoa Touch ,这套完善的框架都被认为是管理大量结构化数据所首选的 Cocoa 框架,尤其是因为使用 Core Data 能大大减少需要手工编写的代码量,就使它更受开发者欢迎了。
44
Core Data 简介• 面向对象的程序员大多都不喜欢用基于 C API
去做数据持久化。• 希望使用面向对象的编程去持久化数据。• 使用 Core Data 是比较好的选择。• 它是支持数据库方式,建立对象图。
– 通常使用 SQLite3
• 它是如何工作的?– 通过可视化的方式建立数据库和对象的映射– 使用面向对象的 API 来查询对象– 使用对象属性访问数据库中对应表的列
55
创建实体• 在数据库中实体对应为“表“,在我们的
代码里映射为”对象”。– 这里 用 Photo 实体来代表照片
1010
点击 +号 , 添加一个实体
修改实体名为 Photo
对应实体类型NSManageObject
给实体添加属性• 属性映射为数据库的“列”,映射为对象属性• thumbnailURL 用于存储 URL, 使用它下载我们的照片缩略
图
1111
点击+ 号来添加属性
和修改实体名一样
属性的类型为” string”. 对应到代码里为NSString
建立两个实体间的关联关系• 建立一个”一对多”关联关系 photos
– 在对象中映射为 (NSSet *)– 一个摄像师拥有很多照片
1515
通过” Add Relationship”来增加关联关系
关联关系名称
指向 Photo 对象它没有” inverse”关系,它们是“ To-Many”的关联关系
双向关联 (inverse 关联关系 )• 在 Photo 实体上,增加 whoTook 关联关系,它指向
Photographer 实体。• whoTook 不是多对一关系,因此它是 NSManagedObject 属性
(而不是 NSSet )
1616
whoTook 是Photos 的逆向关联关系
箭头变成双向
Core Data 数据访问• 关于 Core Data 还有许多其它事情可以做
– 前面部分我们只关心创建实体,属性,关联关系• 如何通过程序方式访问数据?– 需要用 NSManagedObjectContext
• 如何得到 NSManagedObjectContext– 在创建项目时,选择复选框“ User Core Data for storage”
– 应用程序 代理 里有一些代码支持 Core Data– 最特别的是代理中有一个属性” managedObjectContext”– 正是利用这个对象去访问数据库中,创建或查询对象
1818
如何创建一个新对象
1919
•
• NSEntityDescription 类方法返回一个 NSManagedObject.• 所有来自数据库的对象不是 NSManagedObject 就是它的子类• 通过传递参数方式来引用 NSManagedObjectContext
– 上面的代码通常不是在应用程序代理中– 不要把应用程序代理当成全局变量– 所以必须在 API 中传递 NSManagedObjectContext(Controllers 等 )– 通常,在视图控制器如下方式处理 Core Data 的显示
• initInManagedContext: (NSManagedObjectContext *) Context
NSManagedObject *photo = [NSEntityDescription insertNewObejectForEntityForName:@”Photo” inManagedObjectContext: (NSManagedObjectContext *) ctxt];
如何获得属性值• 可以通过以下两个方法来访问
– ( id ) valueForKey: (NSString *)key;– (void) setValue: (id) value forKey:(NSString *)key;
• key 是对象映射中的属性名– 如: @”thumbnailURL”
• value 将被存储到数据库里– 如果值没有被设置,默认是 nil 。– 所有的值都是对象– Binary data 值对应的是 NSData 对象– “To-many” 映射的关联关系值对应为 NSSet 对象• 一切都会为你管理• SQL 自动生成,数据延迟加载等
2020
如何保存数据• 数据修改 ( 写入 ) 都是花生在内存中,除非你 保存
– 任何时候一批数据变化,都应保存– Save: 是 NSManagedObjectContext 的实例方法– 保存之前,需要判断对象是否有改变
• - ( BOOL ) hasChanges;
• 典型的代码块
– 所有错误都可以通过 NSError userInfo 来报告
2121
-( void) saveChangesToObjectsInMyMOC: (NSManagedObjectContext *) context { NSError *error = nil; if ( [context hasChanges] && ![context save:&error]){ NSLog(@”错误! %@”,error,[error userInfo] ); abort();// 在这里生成崩溃 log,用于调试 }
生成的代码 .h
• 只有每一个实体属性对应的 @property
3131
#import <CoreData/CoreData.h>@interface Photo : NSManagedObject {}@property (nonatomic, retain) NSData * thumbnailData;@property (nonatomic, retain) NSString * thumbnailURL;@property (nonatomic, retain) NSManagedObject * whoTook;@end
#import <CoreData/CoreData.h>@class Photo;@interface Photographer : NSManagedObject {}@property (nonatomic, retain) NSSet* photos;@end
生成的代码 .m
•@dynamic – 使用运行期机制拦截对象消息,在这种情况
下, NSManagedObject 使用 valueForKey: 或setValueForKey: 来操作属性
– 使用 . 记号来访问数据库实体
3232
@implementation Photo @dynamic thumbnailData;@dynamic thumbnailURL;@dynamic whoTook;@end
Photo *photo = [NSEntityDescription insertNewObjectForEntityForName:@”Photo” inM..]NSString * myThumbnail = photo.thumbnailURL;Photo.thumbnailData = …Photo.whoTook = …/ 一个摄像师对象,可以通过查询语句创建
NSFetchRequest• 到目前为止,我们可以
– 通过 insertNewObjectForEntityForName:inManagedobjectContext: 来创建持久化对象
– 通过 valueForKey:/setValueForKey 或 @property 来 访问或改变属性值
• 在 Core Data 框架里如何查询数据– 可以通过执行 NSManagedObjectContext 中的 NSFetchRequest 来
获得查询数据• 查询过程中涉及到的四个重要对象– NSEntityDescription 指定查询那个实体(必须)– NSPredicate 指定获取那些实体对象(可选,默认获得所有对象)– NSSortDescription 指定返回数组的排序方式。(可选,随机的)– 指定一次获取多少对象或最大获取多少个对象。(可选,所有对
象)
3333
创建 NSFetchRequest
• 查询代码块
• 通过实体描述来获取想要的对象– request.entity = [NSEntityDescription entityForName:@”Photo” inManagedObjectContext:ctxt];
– 通过 NSEntityDescription 来创建实体描述的实例
– 设置获取数据的大小或最大数
3434
NSFetchRequest *request = [[NSFetchRequest alloc ] init];request.entity = [NSEntityDescription entityForName:@”Photo” inManagedObjectContext:ctxt];request.fetchBatchSize = 20;request.fetchLimit = 100;Request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];Request.predictate = ….;
NSSortDescriptor• 当执行 fetchRequst 对象时,它将返回一个存
NSManagedObject 对象数组。• 数组是“有序的”,因此我们获取数据时通常想
指定顺序。通过给 fetchRequest 一列 “排序描述”用它来描述什么排序方式
• 也可以不用 selector 参数(默认使用的方法 compare: )
• selector: 参数只是一个方法,它可以对每个关键字进行相互比较。
3535
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@”thumbnailURL” ascending: YES selector: (localizedCaseinsensitiveCompare:)];
NSPredicate
• 如何准确指定那些数据是我们想要从数据库中获取的呢?
• predicateWithForm:arguments….– @”uniqueid == %@,[dept objectForKey:@”id”]– “@ in tags”,(NSMagagedObject *)// tags 是 to-many 的关
系– “viewed > %@”,(NSDate *)// viewed 是日期类型的属性– @”name contains[c] %@”,(NSString *)//匹配 name 属性的字符串,大小些敏感
3636
NSString *username =@”davinlei”;NSPredicate *predicate = [NSPredicate predicateWithFormat: @”name contains %@”, username];
NSCompoundPredicate
• 用并且和或的运算方式组合 predicate条件
3737
NSArray * array = [NSArray arrayWithObjects:predicate1,predicate2,nil];NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:array];
综合使用• Photographer 是 NSManagedObject 的子类• 通过 photographerWithName 方法从数据库获取
一个 photographer
• 创建 fechRequest 对象 获取 davinlei 所拍的所有照片
3838
NSManagedObject *photographer = [Photographer photographerWithName:@”davinlei” inManagedObjectContext]
NSFetchRequest *request = [[NSFethcRequest alloc] init];request.entity = [NSEntityDescription entityForName:@”Photo” inManagedObjectContext:ctxt];request.fetchBatchSize = 20;request.soreDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@”title” ascending: YES]; request.predicate = [NSPredicate predicateWithFormat:@”whoTook = %@”,photographer]
fetchRequst 实际获得的结果• 使用 executeFetchRequest: error 方法
– 如果发生异常,则返回 nil(详细错误信息查看 NSErro)– 如果没有任何匹配的对象,则返回空数组– 如果有数据匹配,则返回 NSManagedObjectd 对象数组– 如果不关心错误信息,可以传 NULL 给 error 参数• 遍历结果
3939
NSFetchRequest *request = ……NSError **error = nil;NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
NSManagedObject *photo = [results objectAtIndex:0];For(Photo *photo in results ){….}Photo *photo = [results lastObject];//返回 0 或 1 个对象
删除对象
• 如果对象之间有关联关系?– 如: 当删除 photograther拍的最后一张照片,是否删
除 photograther?– 可以在关联控制地方设置
• 选中“ Createing and Deleting Managed Objects”
4040
[managedObjectContext deleteObject (NSManagedObject *) anObject];