11 Core Data - 斯坦福 iOS

Core Data


就基础而言, 它是一种创建对象的方式, 创建你要处理的 object-c 对象, 并映射到 SQL 或者 XML 数据库.

它是面向对象领域同数据库领域之间的桥梁, Core Data 主要连接的就是 SQL 的后台.

Core Data 是如何工作的呢?
1.首先用 XCode 中的工具创建一个可视的映射.这就是在对象和数据库之间建立映射的方式.

有了这个映射之后,你就可以做很多事情, 但我们将聚集于创建实体,属性,和关系.

创建了映射后, 如何访问代码中的这些东西呢?
我们需要: NSManagedObjectContext

如何得到 NSManagedObjectContext?
有两种方法:

  • 用 NSManagedObjectContext 的 alloc init 方法(课程中未讲)
  • 调用用 UIManagedDocument 类

UIManagedDocument 继承于 UIDocument是一系列用于管理储存的机制.

你可以这样考虑 UIManagedDoument, 它为你容纳你的 Core Data 数据库, 你所做的只是打开或创建一个 UIManagedDocument, 然后抓取它的 ManagedObjectContext, 然后用它来做数据库.

创建本地目录

//创建共享文件管理器
NSFileManager *fileManager = [NSFileManager defaultManager];

//得到用户文件目录的 URL
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];

//在url 后面再添加一个目录文件,只是生成 url 并没有真创建好,参数为目录名
NSURL *url = [documentsDirectory URLByAppendingPathComponent:@"MyDocument"];

1.创建 UIManagedDocument(文档) 对象(只是创建在内存,但还并没有写在磁盘上)

//url: 是将 Core Data 数据存储的地方
UIManagedDocument *document = [UIManagedDocument alloc] initWithFileURL:url];

2.判断磁盘上是否存在

//判断 url 路径是否在本地磁盘上
BOOL fileExists = [NSFileManager defaultManager] fileExistsAtPath:[url path]];

if(fileExists){

    //如果存在,执行 block
    [document openWithCompletionHandler:^(BOOL success){
    /*里面为 block 部分*/
        if(success){
        
            //如果UIManagedDocument(文档)的状态是正常的
            if(document.documentState = = UIDocumentStateNormal){
            
                //取得 document 的 managedObjectContext
                NSManagedObjectContext *context = document.managedObjectContext;
                
            }
        
        }
    }];

}else{

    //如果不存在,就创建文档到磁盘上
    [document saveToURL:url forSavePoeration:UIDocumentSaveForCreating competionHandler:^(BOOL success){
    /*里面为 block 部分*/
    }];

}

中间临时插入:
相同文档上 UIManagedDocument 的多实例

能不能我对文件 URL 进行 alloc init, 来创建一个 UIManagedDocument, 然后其他人对相同文件 URL 进行 alloc init, 这样完全可以, 两者有自身的 ManagedObjectContext ,但 context 都着眼于相同的数据库, 它们都发生变化时, 会发生保存.

但这也有可能出问题, 会容易同时操作时产生冲突. 所以通常多实例, 只有一个能写其它那些只能读.

如何让一个修改了数据库, 另一个也可以自动看到相应的变化? 广播站(NSNotification),进行监听,


现在我们有了NSManagedObjectContext,来自于我们的文档(UIManagedDocument *document)

增加(插入):
假设我要添加一张新照片, 或者是一个新的拍照人到数据库中.

NSManagedObjectContext *context = document.managedObjectContext;

//在 context 上创建了一个 "Photo" 对象,@"Photo" 是实体的名称
NSManagedObject *photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:context];

修改:

现在有了对象了, 要如何设定属性呢(如:标题,whoTook 等), 这要用到 KeyValueCoding 协议, 并且 NSManagedObject 实现了.

用这两个方法来设置属性
- (id)valueForKdy:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;

这些修改只会保存在内存中, 直到你调用 NSManagedObjectContext 的保存方法才会保存到磁盘中.

但这种方法存在一定的问题,比如设置属性的方法都为 id 类型, 很容易出问题. 所以我们创建实体的子类

//注意: 是 Photo 类
Photo *photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:context];

 photo.title = [flickrData objectForKey:FLICKR_PHOTO_TITLE];
photo.lastViewedDate = [DSDate date];
photo.whoTook.name = @".....";

删除:

//调用context 的 deleteObject 方法
[context deleteObject:photo];
//删除对象之后最好,把它设置为 nil
photo = nil;
//删除时 Core Data 会发送下方方法, 执行完后才会删除
- (void)propareForDeletion{

}

查询:

通过 NSFetchRequest(取回请求) 对象来进行查询.你提出请求从数据库中取回一些对象.

查询的步奏:
1.首先你要设置请求(NSFetchRequest)
A.指定要取回的实体(Entity)类型
B.指定要接收多少个对象
C.如何排序,用 NSSortDescriptor(排序描述器)
D.想要哪些实体.用 Predicate(谓词)
2.调用 NSManagedObjectContext 的方法,执行请求

创建 NSSortDescriptor(排序描述器)

//selector 用于在排序过程中对比照片,结果将会依标题排序(其它创建方法看NSSortDescriptor类)
//compare:除了 NSData 对数据库中所有的东西都会做出响应, 只不过 NSString 里localizedStandardCompare: 方法更好
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES selector:@selector(localizedStandardCompare:)];

创建 Predicate(谓词)

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"thumbnailURL contains %@",@"flickr-5"];

进行查询(设置请求)

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
request.fetchBatchSize = 20;
request.fetchLimit = 100;
request.sortDescriptors = @[sortDescriptor];
request.predicate = predicate;

执行请求
使用 NSManagedObjectContext 中的executeFetchRequest 方法

NSArray *photographers = [context executeFetchRequest:request error:NULL];

关于 Core Data 的线程安全
NSManagedObjectContext 线程并不安全,你不能简单在多线程中使用它, 不过你可以通过安全访问它们

任何你希望对 context 做的事情,都可以在 performBlock 中执行

//调用 context 的 performBlock:方法
[context performBlock:^{


}]

Core Data 与 TableView 的共同协作

有两种方法可以让 FetchedResultsController(取回结果控制器) 同表格关联起来.
一是使用FetchedResultsController实现所有的UITableViewDataSource的东西.
二是设置FetchedResultsController的委托, 使用委托方法来监视.

使用 NSFetchedResultsController, 它的作用是将一个 NSFetchRequest, 和 UITableView 关联起来, Fetch取回的任何东西都总会显示在 TableView 中.

工作方面 FetchedResultsController 有两部分,
一是它回答了 UITableViewDataSource 中的所有问题
二是可以告诉你在给定行中显示的是什么实体

创建一个FetchedResultsController

//cache: 缓存,它会缓存取回的结果. 如果其值是 nil ,就会永久缓存在磁盘上(不是内存)
//sectionNameKeyPath:你指定要取回的对象中, 哪个属性是 section 的名称, 然后它会将表格分成 section
//如果你要使用 sectionNameKeyPaht 尝试把 section 放到 tableView 中, 排序描述器就需要匹配 section 键, 换言之, 表中的行, 你取回的照片, 必须和 section header 具有相同顺序
//sectionNameKeyPath控制返回的sectiond
NSFetchedResultsController *frc = [[FetchedResultsController alloc] initWithFetchRequest:(NSFetchRequest *)fetchRequest managedObjectContext:(NSManagedObjectContext *)context sectionNameKeyPath:(NSString *)sectionNameKeyPath cacheName:(NSString *)name];

FetchedResultsController 还有一个委托, 使用这个委托可以监视 Core Data 中发生的事情, 当有变化时 FetchRequest 会受影响, 从而让你的表格变化.

//didChangeObject:监听的广播站
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath

有两种方法可以让 FetchedResultsController同表格关联起来

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

推荐阅读更多精彩内容