iOS学习笔记18-CoreData你懂的

作者: 执着丶执念 | 来源:发表于2016-04-04 10:34 被阅读1196次

    一、CoreData介绍

    CoreData是iOS5之后新出来的的一个框架, 是对SQLite进行一层封装升级后的一种数据持久化方式。
    它提供了对象<-->关系映射的功能,即能够将OC对象转化为数据存储到SQLite数据库文件中,同时也能将数据库中的数据还原成OC对象。相较于SQLite,我们使用CoreData就不需要再编写任何SQL语句,再也不去纠结SQL语句怎么写了O(∩_∩)O哈~。

    二、CoreData核心结构图

    先来张官方的图:
    这四者的关系图
    • PersistentObjectStore:存储持久对象的数据库(例如SQLite,注意CoreData也支持其他类型的数据存储,例如xml、二进制数据等)。
    • ManagedObjectModel:对象模型,对应Xcode中创建的模型文件。
    • PersistentStoreCoordinator:对象模型和实体类之间的转换协调器,用于管理不同存储对象的上下文。
    • ManagedObjectContext:对象管理上下文,负责实体对象和数据库之间的交互。
    说了这么多,可能你还是懵逼的,下面是我的理解图:
    我对CoreData的理解
    最底层的就是PersistentObjectStore,也就是我们实际存储数据的结构;
    图中的模型就是ManagedObjectModel,就是数据转化为对象的模板;
    以SQLite数据库为例:
    • 读取数据库的数据时,数据库数据先进入数据解析器,根据对应的模板,生成对应的关联对象。
    • 向数据库插入数据时,对象管理器先根据实体描述创建一个空对象,对该对象进行初始化,然后经过数据解析器,根据对应的模板,转化为数据库的数据,插入数据库中。
    • 更新数据库数据时,对象管理器需要先读取数据库的数据,拿到相互关联的对象,对该对象进行修改,修改的数据通过数据解析器,转化为数据库的更新数据,对数据库更新。

    这些还是要在使用中进行加深理解

    三、CoreData使用

    1. 添加框架

    • 添加CoreData.framework
    • #import导入头文件<CoreData/CoreData.h>

    2. 数据模板和对象模型

    看上面的图就知道,我们需要首先创建一个数据模板,即ManagedObjectModel

    下面是创建数据模板的步骤【是图形化操作,所以都是图片】:
    第一步 创建数据模板文件 第二步 点开数据模板文件,添加实体,添加属性 第三步 添加关系,可以控制是一对多还是多对多 点击style,可以查看直观的关系图 第四步 根据数据模板创建对象模型文件

    点击Next,会进入一个数据模板文件的选择打钩,再点Next,会进入一个实体的选择打钩,选完点Next就会自动生成对象模型文件。


    自动生成对象模型文件
    • 所有的实体类型都继承于NSManagedObject,每个NSManagedObject对象对应着数据库中一条记录。
    • 集合属性(例如数组)会自动生成访问此属性的分类方法。
    • 使用@dynamic代表具体属性实现,具体实现细节不需要开发人员关心。

    3. 创建对象管理上下文

    创建对象管理上下文ManagedObjectContext可以细分为:
    1. 加载模型文件
    1. 指定数据存储路径
    2. 创建对应数据类型的存储
    3. 创建管理对象上下方并指定存储
    下面是实例代码:
    - (NSManagedObjectContext *)createDbContext{
        //打开模型文件,参数为nil则打开包中所有模型文件并合并成一个
        NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
        //创建数据解析器
        NSPersistentStoreCoordinator *storeCoordinator = 
                [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
        //创建数据库保存路径
        NSString *dir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject;
        NSString *path = [dir stringByAppendingPathComponent:@"myDatabase.db"];
        NSURL *url = [NSURL fileURLWithPath:path];
        //添加SQLite持久存储到解析器
        NSError *error;
        [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
                                       configuration:nil 
                                                 URL:url 
                                             options:nil 
                                               error:&error];
        
        NSManagedObjectContext *context = nil;
        if( !error ){
            //创建对象管理上下文,并设置数据解析器
            context = [[NSManagedObjectContext alloc] init];
            context.persistentStoreCoordinator = storeCoordinator;
            NSLog(@"数据库打开成功!");
        }else{
            NSLog(@"数据库打开失败!错误:%@",error.localizedDescription);
        }
        return context;
    }
    

    4. 插入数据

    插入数据我们需要创建一个实体对象,并把这个对象关联上对象管理器,我们创建实体对象需要使用到NSEntityDescription(实体描述类)的类方法

    下面是实现代码:
    - (void)addClassTest
    {
        //添加一个对象
        Classes *classes = [NSEntityDescription insertNewObjectForEntityForName:@"Classes" 
                                                         inManagedObjectContext:self.context];
        classes.c_id = 301;
        classes.c_name = @"高三(1)班";
        NSError *error;
        //保存上下文,这里需要注意,增、删、改操作完最后必须调用管理对象上下文的保存方法,否则操作不会执行。
        if (![self.context save:&error]) {
            NSLog(@"添加过程中发生错误,错误信息:%@!",error.localizedDescription);
        }
    }
    

    5. 删除数据

    删除数据,只需要删除关联的对象就行了:
    - (void)removeClasses:(Classes *classes){
        [self.context deleteObject:classes];
        NSError *error;
        if (![self.context save:&error]) {
            NSLog(@"删除过程中发生错误,错误信息:%@!",error.localizedDescription);
        }
    }
    

    6. 查询数据

    查询数据需要处理查询结果,要用到两个类:
    • NSFetchRequest:获取数据的请求
    • NSPredicate :请求的谓词,也就是获取数据的要求
    1. 查询一个对象只有唯一一个关联对象的情况

    例如查找用户名为“Binger”的微博(一个微博只能属于一个用户),通过keypath查询:

    - (NSArray *)getStatusByUserName:(NSString *)name{
        //创建查询请求
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Status"];
        //创建谓词,设置获取数据的条件
        request.predicate = [NSPredicate predicateWithFormat:@"user.name=%@",name];
        //执行对象管理上下文的查询方法
        NSArray *array = [self.context executeFetchRequest:request error:nil];
        return  array;
    }
    
    2. 查询一个对象有多个关联对象的情况

    例如查找发送微博内容中包含“Watch”并且用户昵称为“小娜”的用户(一个用户有多条微博)

    - (NSArray *)getUsersByStatusText:(NSString *)text screenName:(NSString *)screenName{
        //创建查询请求
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Status"];
        //设置查询条件
        request.predicate = [NSPredicate predicateWithFormat:@"text LIKE '*Watch*'",text];
        //获取查询结果
        NSArray *statuses = [self.context executeFetchRequest:request error:nil];
        //下面是用谓词对上面的结果进行过滤
        NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"user.screenName=%@",screenName];
        //对查询结果再进行过滤
        NSArray *users = [statuses filteredArrayUsingPredicate:userPredicate];
        return users;
    }
    

    7. 修改数据

    只需要拿到对应的关联对象,直接修改,然后保存

    - (void)modifyClasses:(Classes *)classes
    {    
        classes.name = @"吊炸天毕业(1)班";
        NSError *error;
        if (![self.context save:&error]) {
            NSLog(@"修改过程中发生错误,错误信息:%@",error.localizedDescription);    
        }
    }
    

    四、CoreData调试

    事实上在Xcode中是支持CoreData调试的,具体操作:
    • Product->Scheme
    • Scheme->Edit Scheme
    • Edit Scheme->Run
    • Run->Arguments
      依次添加两个参数(注意参数顺序不能错):
    CoreData调试设置

    然后在运行程序过程中,如果操作了数据库,就会将SQL语句打印在输出面板。

    注意:如果模型发生了变化,此时可以重新生成实体类文件,但是所生成的数据库并不会自动更新,这时需要考虑重新生成数据库并迁移原有的数据。

    这一节感觉写的不好,很多东西没法写太细,很多概念也不好理解,希望大家体谅,有建议可以在下方的评论区提出,O(∩_∩)O哈!

    相关文章

      网友评论

      • _心暖:虽然现在是个菜逼没看懂,但是先关注了:yum:
        执着丶执念:@_心暖 谢谢关注,这里很多干货的,\(^o^)/~
      • qinfensky:见到很多文章包括此文中都提到了"上下文",一直没能有概念对应上去,能讲讲上下文到底是什么东西吗?该什么时候用?
        qinfensky:@执着_执念 具体的以后我再和你探讨,可能现在看的资料不够多。
        执着丶执念:@qinfensky 就像图形上下文,用于管理全局的,当它是一个管理类就行了,我们需要保持一个上下文不被销毁

      本文标题:iOS学习笔记18-CoreData你懂的

      本文链接:https://www.haomeiwen.com/subject/axuulttx.html