IOS开发之一:CoreData入门与进阶

CoreData提供了一种简便的对象持久化管理方法,使你可以不用关心数据的存储,只需要关心对象的增加、删除、更改、读写。

并且CoreData提供模型操作方式,可以和UITableView完美的进行结合使用,不用写sql语句,降低出错率.

CoreData核心类:

基本概念
托管对象(managed object)
managed object代表你想要存储的实例化的一个对象。这在概念上类似于SQL中的一条记录, 并且通常也包含一些域,这些域对应于你想要保存的对象的属性。

数据存储(data store)
Core Data支持4中类型的数据存储:SQLiteStore, XMLStore, BinaryStore, InMemoryStore。

托管对象上下文(managed object context)
托管对象上下文类似于应用程序和数据存储之间的一块缓冲区。这块缓冲区包含所有未被写入数据存储的托管对象。你可以添加、删除、更改缓冲区内的托管对象。在很多时候,当你需要读、插入、删除,修改对象时,都需要调用托管对象上下文的方法。Managed Object Context 参与对数据对象进行各种操作的全过程,并监测数据对象的变化.
 
持久化存储协调器(persistent store coordinator)
Persistent Store Coordinator 相当于数据文件管理器,处理底层的对数据文件的读取与写入。一般我们无需与它打交道。持久化存储协调器处理到数据存储的连接,并且包含一些底层信息,像用到数据存储的名字和位置。这个类通常被托管对象上下文用到。
 
托管对象模型(managed object model)
managed object model是描述应用程序的数据模型,这个模型包含实体(Entity),属性(Property),读取请求(Fetch Request)等。(加载模型文件.xcdatamodeld)
开发步骤总结:
1.初始化NSManagedObjectModel对象,加载模型文件,读取app中的所有实体信息
2.初始化NSPersistentStoreCoordinator对象,添加持久化库(这里采取SQLite数据库)
3.初始化NSManagedObjectContext对象,拿到这个上下文对象操作实体,进行CRUD操作
 
 首先我们新建一个工程命名为CoreDataTest,并新建一个单例,命名为CoreDataManager
+(instancetype)sharedCoreDataManager
{
    static CoreDataManager *manager;
    static dispatch_once_t pre;
    dispatch_once(&pre, ^{
        manager = [[CoreDataManager alloc] init];
    });
    return manager;
}
 我们使用单例来获取coredata的各种管理.
接着我们为CoreDataManager添加(开发步骤总结)所说的三个成员属性.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface CoreDataManager : NSObject

@property(readonly,nonatomic,strong)NSManagedObjectContext *managedObjectContext;
@property(readonly,nonatomic,strong)NSManagedObjectModel *managedObjectModel;
@property(readonly,nonatomic,strong)NSPersistentStoreCoordinator *persistentStoreCoordinator;

+(instancetype)sharedCoreDataManager;

@end

紧接着,创建CoreData所需要的文件.xcdatamodeld文件,命名为Person

蓝后,我们打开CoreDataManager.m文件,添加实现代码

//NSManagedObjectModel实际上就是加载xcdatamodeld文件,读取里面的实体等信息
-(NSManagedObjectModel *)managedObjModel
{
    if (_managedObjModel) {
        return _managedObjModel;
    }
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"Person" withExtension:@"momd"];
    _managedObjModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
    return _managedObjModel;
}

//持久化存储助理:相当于数据库的连接器
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjModel];
    // 构建SQLite数据库文件的路径
    NSURL *storeUrl = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"Person.sqlite"];
    
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    //添加数据库
    NSError *error;
    NSPersistentStore *store = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
    
    if (store == nil) {
        // 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 *)managedObjContext
{
    if (!_managedObjContext) {
        _managedObjContext = [[NSManagedObjectContext alloc] init];
        [_managedObjContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
    }
    return _managedObjContext;
}

 接着,我们为CoreDataManager类添加一个保存方法:

- (void)saveContext {
    NSManagedObjectContext *managedObjectContext = self.managedObjContext;
    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();
        }
    }
}

至此,我们的数据库操作的类,已经创建完成,可以使用了。

接下来,我们开始简单的使用.我们创建一个tableViewController该控制的右上方有一个有一个+号button。

我们将window的根控制器设置为一个导航控制器,导航控制器的根控制器为一个tableViewController。

1.首先创建实体。该实体有一个name,age,height.

2.我们实现点击+号button添加一条数据,向左滑动cell删除一条数据。点击cell实现修改其名称为changedName,实现简单的增,删,改,查.

我们在viewDidLoad方法里读取本地是否有缓存数据,实现查询数据:

- (void)viewDidLoad {
    [super viewDidLoad];
    //右上角+号按钮
    UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightBtn];
    [rightBtn addTarget:self action:@selector(add) forControlEvents:UIControlEventTouchDown];
    
    self.managedCtx = [CoreDataManager sharedCoreDataManager].managedObjContext;
    
    //根据实体名称创建一个FetchRequest
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Person"];
    //执行查询,该方法是NSManagedObjectContext的对象方法,返回一个数组
    NSArray *personArr = [[CoreDataManager sharedCoreDataManager].managedObjContext executeFetchRequest:request error:nil];
    _sourceArr = [NSMutableArray arrayWithArray:personArr];
}

当我们点击右上角的+号时我们插入一条数据,并刷新表格

- (void)add
{
    //根据实体创建出一个NSManagedObject对象
    NSManagedObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedCtx];
    
    NSString *name = [NSString stringWithFormat:@"testName%d",self.index];
    NSNumber *height = [NSNumber numberWithDouble:arc4random()];
    //设置NSManagedObject对象的值kvc的方式
    [obj setValue:height forKey:@"height"];
    [obj setValue:name forKey:@"name"];
    //保存
    [[CoreDataManager sharedCoreDataManager] saveContext];
    
    self.index++;
    
    [_sourceArr addObject:obj];
    
    [self.tableView reloadData];
    
}

点击某一行表格的时候,修改name属性

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //取出对应的NSManagedObject对象
    NSManagedObject *obj = _sourceArr[indexPath.row];
    //修改名称
    [obj setValue:@"changedName" forKey:@"name"];
    //保存
    [[CoreDataManager sharedCoreDataManager] saveContext];
    [self.tableView reloadData];
}

滑动cell的时候删除一条数据,并刷新表格

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //首先我们取得查询数组中的所要删除的NSManagedObject对象
        NSManagedObject *obj =  _sourceArr[indexPath.row];
        [_sourceArr removeObjectAtIndex:indexPath.row];
        
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        
        [self.tableView reloadData];
        
        //执行删除操作
        [[CoreDataManager sharedCoreDataManager].managedObjContext deleteObject:obj];
        //保存
        [[CoreDataManager sharedCoreDataManager] saveContext];
        
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
}

至此,我们实现的CoreData的简单的,插入,删除,修改和查询功能,CoreData的功能强大,可以存储大量数据,并且可以利用

NSFetchedResultsController和tableview进行结合使用,并且可以生成NSManagerObject类和属性,而无需使用KVC的方式进行存储值,降低出错。

下一篇,我们将一起来学习CoreData与tableView的结合使用,和多线程加载大量数据.

 

posted @ 2015-05-19 15:18  华洛  阅读(132)  评论(0)    收藏  举报