您的位置:首页 > 移动开发 > IOS开发

Coredata — 入门使用

2016-04-09 14:45 344 查看
CoreData的底层实现虽然是使用的sqlite数据库,可是CoreData在使用起来可是和sqlite大相径庭,可能你会发现你连一句sql语句都不要写。CoreData存在于应用程序和持久化存储区之间,扮演了桥梁的角色,将托管的对象映射到持久化存储区当中。


1.设置上下文

在代码开始之前还需要添加CoreData框架,并在合适的地方引入头文件<CoreData/CoreData.h>:




    // 从应用程序包中加载模型文件
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
// 传入模型对象,初始化NSPersistentStoreCoordinator
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// 构建SQLite数据库文件的路径
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"model.data"];
// 将数据库路径转成URL
NSURL *url = [NSURL fileURLWithPath:filePath];
// 添加持久化存储库,这里使用SQLite作为存储库
NSError *error = nil;
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
// 判断数据库是否添加成功
if (store == nil) {
[NSException raise:@"添加数据库错误" format:@"%@", [error localizedDescription]];
}
// 初始化上下文
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// 设置persistentStoreCoordinator属性
context.persistentStoreCoordinator = psc;


2.添加数据

    // 创建一个Husband实体对象,传入上下文
NSManagedObject *husband = [NSEntityDescription insertNewObjectForEntityForName:@"Husband" inManagedObjectContext:context];
// 通过键值编码的方式设置Husband的name属性
[husband setValue:@"jack" forKey:@"name"];
// 通过coredata生成的实体类来创建一个Wife实体对象,传入上下文
Wife *wife = [NSEntityDescription insertNewObjectForEntityForName:@"Wife" inManagedObjectContext:context];
// 通过setter方法设置属性
wife.name = @"rose";
// 设置Husband和Wife之间的关联关系(一方关联,另一方自动关联)
wife.husband = husband;
// 利用上下文对象,将数据同步到持久化存储库
BOOL success = [context save:&error];
if (!success) {
[NSException raise:@"访问数据库错误" format:@"%@", [error localizedDescription]];
}
// 如果是想做更新操作:需要将实体对象先查询出来,在更改了实体对象的属性后调用[context save:&error],就能将更改的数据同步到数据库


 3.查询数据

    // 初始化一个查询请求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 设置要查询的实体
request.entity = [NSEntityDescription entityForName:@"Husband" inManagedObjectContext:context];
// 设置排序(按照name降序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];
// 设置条件过滤(搜索name中包含字符串"ja"的记录)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*ja*"];
request.predicate = predicate;
// 执行请求,返回一个数组
NSArray *objs = [context executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
}
// 遍历数据
for (NSManagedObject *obj in objs) {
NSLog(@"name=%@", [obj valueForKey:@"name"]);
// 实体属性中包含另一个实体,不需要再次设置查询请求,Core Data会根据关联关系查询到关联的实体信息
NSLog(@"wife = %@", [[obj valueForKey:@"wife"] valueForKey:@"name"]);
}

fetchRequest相当于sql查询语句的包装类,需要用setEntity方法,来指定具体查询的实体结构(表结构);

通过NSEntityDescription的entityForName方法来,返回指向该具体实体结构的指针;

然后调用executeFetchRequest:error:方法,来执行查询操作,如果操作成功,则返回对应的数据记录数组;

其中,可以通过NSManagedObject数据记录对象里关联的属性,查询另一个数据记录对象里的属性;

CoreData不会根据实体中的关联关系立即获取相应的关联对象,比如通过CoreData取出Husband实体时,并不会立即查询相关联的Wife实体;当应用真的需要使用Wife时,才会再次查询数据库,加载Wife实体的信息。这个就是CoreData的延迟加载机制。





4.删除数据

Core Data的增删改使用的方法都是save:方法,在上下文调用save方法之前,所有的数据修改都是发生在内存中的,只有调用save方法后,上下文中发生的数据修改才会被写入到持久化存储区。

获取到需要删除的实体对象之后,调用deleteObject:方法就可以从上下文中删除这个实体对象了,最后需要调用save:方法同步修改到数据库中:
    // 初始化一个查询请求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 设置要查询的实体
request.entity = [NSEntityDescription entityForName:@"Husband" inManagedObjectContext:context];
// 设置条件过滤(搜索name等于jack2的实体)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", @"jack2"];
request.predicate = predicate;
// 执行请求,返回一个数组
NSArray *objs = [context executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
}
// 遍历数据
for (NSManagedObject *obj in objs) {
// 传入需要删除的实体对象
[context deleteObject:obj];
// 将结果同步到数据库
[context save:&error];
if (error) {
[NSException raise:@"删除错误" format:@"%@", [error localizedDescription]];
}
}


5.新建工程时勾选Use Core Data选项的情况

在新建工程时使用CoreData,系统会帮我们在AppDelegate中搭建好一个上下文环境,我们可以在其他的controller中去使用这个context,省去了自己搭建上下文的操作,使用起来非常简便。

AppDelegate.h中:
@interface AppDelegate : UIResponder
 
@property (strong, nonatomic) UIWindow *window;
 
// 搭建上下文环境需要使用的对象
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
 
// 保存实体对象到数据库中
- (void)saveContext;
// 取得程序沙盒路径的URL
- (NSURL *)applicationDocumentsDirectory;
 
 
@end

AppDelegate.m中:
#pragma mark - Core Data stack
 
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
 
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "edu.hcit.qqqqq" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
 
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
 
/**************************************************************************************************/
// model 是模型文件的名称,默认是和项目名称相同的
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"model" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
 
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}

// Create the coordinator and store

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

/**************************************************************************************************/
// 下面的数据库 model.sqlite 是存储实体数据的数据库
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"model.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}

return _persistentStoreCoordinator;
}
 
 
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}

#pragma mark - Core Data Saving support
 
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}

如果在一个已有的工程中添加CoreData,搭建上下文时可以新建一个使用CoreData的工程,将上述的代码拷贝到已有工程,在AppDelegate.m中将模型文件的名称和数据库名称稍作修改即可,数据的操作方法与上文类似。


6.打印隐藏的SQL语句

在Edit Scheme中选择Run,之后进入Arguments标签,添加参数:“-com.apple.CoreData.SQLDebug 1”









打开SQL语句隐藏开关后,程序在运行时,debug日志里会打印程序执行的SQL语句:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 数据 存储