《CoreData》系列(一)
发表于|更新于
|阅读量:
《题外篇》
学习这个东西贵在日积月累,而且事情往往说起来容易,做起来难,我是一个资深dota玩家,从dota1到dota2,从大学到工作,从2008年到2015年。一直看2009的视频,经常吐槽09视频更新速度慢,但是细细想想,09能保持优酷更新401(最近查看)期视频。又有多少人能做的到。
故而最近下了一个决定,每周五务必更新一篇技术博客,就看看自己能坚持多久。
《正文》
1 概述
本系列研究讨论的是iOS开发中的一种数据持久化技术-coredata。coredata、sqlite、fmdb的优缺点不是我要讨论的重点
这个系列的blog主要会研究讨论以下几点
1.快速搭建coredata环境,主要是连接数据库、创建数据库托管对象模型(NSManagerObject)、如何保存数据、查询数据?
2.coredata升级以及数据迁移的三种方式。
3.coredata与viewcontroller的结合,通过NSFetchedResultController使用coredata数据。
4.导入默认数据和前后台context。
5.关系
2 环境搭建
2.1 导入《CoreData》的framework
默认读者知道如何创建一个空白的项目,建立好空白项目之后,搜索coredata按图2-1操作,点击添加完成framework的引入。
2.2 创建Model
完成上述第一步,意味着我们已经可以使用CoreData提供的接口API了,接下来就是如何使用的事儿了。创建一个CoreData文件夹,专门用来放CoreData引擎,创建好文件夹后,右键点击选择newfile,然后按照图2-2所示创建数据库模型文件,并将其命名为Model,然后点击Model,添加Entity(表\Class),添加Attribute(字段\属性),到这一部,基本上就把Model,创建出来了。并且里面有了数据模型结构,接下来的问题就是,连接数据库,根据模型创建托管对象了
2.3 代码连接数据库
好啦,前面只是开胃菜,真正的大餐马上就要来了,在吃大餐前,有一些名称需要说明下
1.NSManagedObjectContext - 托管对象上下文,用来干嘛的呢?望文生意,用来管理托管对象的,负责从数据库中获取对象、保存对象、删除对象等等操作。
2.NSManagedObjectModel - 对象模型, 根据我们上面创建的数据模型,创建出托管对象模型,(类似于加工厂的概念,能够用来生产对象的模子)
3.NSPersistentStoreCoordinator - 持久化存储协调器,包含数据库的名称、存储数据类型(Sqlite、Xml、内存)、位置等信息
4.NSPersistentStore - 持久化存储区
另外再附一张图来说明这几者的依赖关系
由于CoreData管理数据的过程较为通用,个人觉的还是封装成一个管理对象较好,方便以后代码复用,这里创建一个CoreDataHelper的类,专门用来管理数据对象,该类的头文件如下
1 2 3 4 5 6 7 8 9 10 11
| #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @interface CoreDataHelper : NSObject @property (nonatomic, strong) NSManagedObjectContext *context; @property (nonatomic, strong) NSManagedObjectModel *model; @property (nonatomic, strong) NSPersistentStoreCoordinator *coordinate; @property (nonatomic, strong) NSPersistentStore *store; - (id)init; - (void)loadStore; - (void)setupCoreData; - (void)saveContext;
|
CoreDataHelp的实现文件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #import "CoreDataHelper.h" static NSString *storeFileName = @"demo.sqlite"; @implementation CoreDataHelper #pragma mark - PATHS - (NSString *)applicationDocumentDirectory { if (debug) { NSLog(@"Running %@ '%@'",[self class],NSStringFromSelector(_cmd)); } NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); return [paths lastObject]; } - (NSURL *)applicationStoreDirectory { if (debug) { NSLog(@"Running %@ '%@'",[self class],NSStringFromSelector(_cmd)); } NSURL *url = [[NSURL fileURLWithPath:[self applicationDocumentDirectory]] URLByAppendingPathComponent:@"stores"]; if (![[NSFileManager defaultManager]fileExistsAtPath:[url path]]) { NSError *error = nil; BOOL success = [[NSFileManager defaultManager]createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error]; if (success) { if (debug) { NSLog(@"success create directory!"); } }else{ NSLog(@"failed create directory!"); } } return url; } - (NSURL *)storeUrl { NSURL *storeUrl = [[self applicationStoreDirectory]URLByAppendingPathComponent:storeFileName]; NSLog(@"storeurl = %@",storeUrl); return storeUrl; } #pragma mark - SETUP - (id)init { if (self) { _model = [NSManagedObjectModel mergedModelFromBundles:nil]; _coordinate = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:_model]; _context = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType]; [_context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; [_context setPersistentStoreCoordinator:_coordinate]; _importContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [_importContext performBlock:^{ [_importContext setPersistentStoreCoordinator:_coordinate]; [_importContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; [_importContext setUndoManager:nil]; }]; } return self; } - (void)loadStore { if (debug) { NSLog(@"Running %@ ,'%@'",[self class], NSStringFromSelector(_cmd)); } if (_store) { return; } NSError *error; NSDictionary *option = @{NSMigratePersistentStoresAutomaticallyOption:@(YES), NSInferMappingModelAutomaticallyOption:@(YES), NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}}; _store = [_coordinate addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeUrl] options:option error:&error]; if (!_store) { if (debug) { NSLog(@"failed load store,error = %@",error); abort(); } } else{ NSLog(@"successfully add store : %@",_store); } } - (void)setupCoreData { [self loadStore]; } - (void)saveContext { if ([_context hasChanges]) { NSError *error = nil; if ([_context save:&error]) { NSLog(@"context save successfully"); }else{ NSLog(@"failed save %@",error); } }else{ NSLog(@"skipped context save , there is no changes"); } } @end
|
2.4 最后附上查询和保存数据库的代码
在AppDelegate.m文件里写一个方法,用来初始化CoreData数据库
1 2 3 4 5 6 7 8 9 10 11 12
| - (CoreDataHelper *)cdh { if (!_cdh) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _cdh = [CoreDataHelper new]; }); [_cdh setupCoreData]; } return _cdh; }
|
下面是插入数据,查询、保存数据的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (void)demo { Item *bananer = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:[[self cdh] context]]; bananer.unit = kg; bananer.name = @"bananer"; Item *oranger = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:[[self cdh] context]]; oranger.unit = kg; oranger.name = @"Oranger"; NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Item"]; NSArray *result = [[[self cdh]context] executeFetchRequest:request error:nil]; for (Item *item in result) { if (debug) { NSLog(@"item.name = %@",item.name); } } [[self cdh]saveContext]; }
|
2.5 小结
经过这么一番下来,终于将CoreData技术应用到我们的项目中了,我们现在能做到,把数据插入到数据库、也能从数据库中读取出数据来,也能保存数据。但是要注意这才是刚刚开始,接下来还有更多的coredata问题等着我们,比方说下节要介绍的数据迁移问题。