iOS 数据持久化 CoreData

Posted HeathHsia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 数据持久化 CoreData相关的知识,希望对你有一定的参考价值。

 

本文是关于http://www.cnblogs.com/kenshincui/p/4077833.html#autoid-3-1-0整理的


          CoreData是ios3.0后引入的数据持久化解决方案, 是一种对象关系映射(ORM), 例如java后台中的Hibernate, iOS中ORM框架首先CoreData, 这是官方推荐的 不需要借助第三方框架,实际上是对sqlite的封装,提供了更高级的持久化方式, 在数据库操作时, 不需要使用sql语句, 也可以直接操作数据库

          ORM框架的作用:将关系数据库中的表(实体)转换成程序中的对象, 其本质还是对数据库的操作, CoreData将对象关系的映射简化了

           使用CoreData进行数据库存取并不需要手动创建数据库, 这个过程完全有CoreData框架完成, 开发人员面对的是模型, 主要的工作就是把模型创建起来, 具体的数据库如何创建也不用管,

            CoreData与SQLite相比较, SQLite比较原始, 操作比较复杂, 使用的是C的函数对数据库进行的操作, 但是CoreData不能跨平台, SQLite能够跨平台, 可控性更强, 更加轻量级.


下面简单的学习下CoreData的使用:


1. 创建工程的时候要勾选 user CoreData





2. 在Appdelegate中会自动生成以下对象和方法





其中 各个对象的作用:(NSManagerObjectContext 比较重要)

  • Persistent Object Store:可以理解为存储持久对象的数据库(例如SQLite,注意Core Data也支持其他类型的数据存储,例如xml、二进制数据等)。
  • Managed Object Model:对象模型,对应Xcode中创建的模型文件。
  • Persistent Store Coordinator:对象模型和实体类之间的转换协调器,用于管理不同存储对象的上下文。
  • Managed Object Context:对象管理上下文,负责实体对象和数据库之间的交互。

3. 创建实体模型和关系:



模型创建的过程中注意:

  • 实体对象不需要创建ID主键,Attributes中应该是有意义属性(创建过程中应该考虑对象的属性而不是数据库中表有几个字段,尽管多数属性会对应表的字段)。
  • 所有的属性应该指定具体类型(尽管在SQLite中可以不指定),因为实体对象会对应生成ObjC模型类。
  • 实体对象中其他实体对象类型的属性应该通过Relationships建立,并且注意实体之间的对应关系(例如一个用户有多条微博,而一条微博则只属于一个用户,用户和微博形成一对多的关系)。

4. 根据上面的模型文件(.xcdatamodeld文件)生成具体的实体类.



每个实体类系统自动生成了4个文件User.h, User.m (User的CoreDataProperties的类目)




需要注意的是以下几点:

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

5. 创建好实体和关系, 就可以对数据进行增删改查的操作了:

CoreData的增删改查的操作主要是基于NSManagerObjectContext, 创建上下文, 保存数据

这里可以使用Appdelegate提供的NSManagerObjectContext这个对象

增加数据: 需要调用NSEntityDescription返回一个实体对象, 然后设置对象的属性, 保存上下文(进行增删改操作的时候, 一定要调用管理上下文的保存方法, 否则操作不会执行)

<span style="font-size:18px;">// 添加数据
- (IBAction)add:(id)sender {
    // 用NSEntityDescription创建实体对象
    User *user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.managerObjectContext];
    user.name = @"Xia";
    user.age = @"18";
    user.time = [NSDate dateWithTimeIntervalSinceNow:0];
    NSError *error;
    // 保存上下文
    if (![self.managerObjectContext save:&error]) {
        NSLog(@"添加过程中的错误信息---%@", error.localizedDescription);
    }
}</span>

查询数据: 通过谓词来实现的, 首先创建一个请求, 设置请求的谓词, 调用上下文执行

注意: 下面有关于NSPredicate拓展

<span style="font-size:18px;">// 查询数据
- (IBAction)equery:(id)sender {
    // 查询获取请求, 设置查询哪个实体 EntityName
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    // NSFetchRequest 有个属性 谓词 predicate(NSPredicate类型)
    // 类似于查询语句的查询条件   用来条件查询
    
    // 查询 user表中 name是Xia的User
    request.predicate = [NSPredicate predicateWithFormat:@"name='Xia'"];
    
    // 也可以使用下面的查询语句格式
//    NSString *name = @"Xia";
//    request.predicate = [NSPredicate predicateWithFormat:@"name like [cd] %@", name];
    NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil];
}</span>

删除数据

<span style="font-size:18px;">// 删除数据
- (IBAction)delete:(id)sender {
    
    // 先获取表里的所有数据
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil];
    
    // 对表里数据的数组进行遍历
    for (User *user in array) {
        // 条件删除
        if ([user.name isEqualToString:@"Xia"]) {
            [self.managerObjectContext deleteObject:user];
        }
        
    }
    
    NSError *error;
    // 保存上下文
    if (![self.managerObjectContext save:&error]) {
        NSLog(@"删除过程中发生的错误信息 ----- %@", error.localizedDescription);
    }
}</span>

更新数据

<span style="font-size:18px;">// 更新数据
- (IBAction)update:(id)sender {
    // 先获取某个实体
    User *user = [self getUserByUserName:@"Xia"];
    
    // 修改实体的属性
    user.name = @"Yan";
    user.age = @"20";
    
    NSError *error;
    // 保存上下文
    if (![self.managerObjectContext save:&error]) {
        NSLog(@"更新数据发生错误 错误信息----%@", error.localizedDescription);
    }
}


// 通过username 获取 User实体类
- (User *)getUserByUserName:(NSString *)username
{
    // User *user = [[User alloc] init];
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil];
    for (User *auser in array) {
        if ([auser.name isEqualToString:username]) {
            return auser;
       
        }
    }
    return nil;
}</span>

 关于NSPreidicate的拓展

    NSPredicate用于查询和过滤
    在SQL中作为查询条件通常用WHERE,但在COREDATA中作为查询条件就可以用到NSPredicate.
    NSPredicate 不单可以和COREDATA中的FetchRequest 配合使用。也可以与NSArray配合使用。
    NSPredicate 中支持的关键词和条件符:
    

    1、>,<,>=,<=,= 比较运算符。

    
    如:
    
    NSPredicate * qcondition= [NSPredicate predicateWithFormat:@"salary >= 10000"];

    2、字符串操作(包含):BEGINSWITH、ENDSWITH、CONTAINS

    
    如:
    
    @"employee.name BEGINSWITH[cd] '李'" //姓李的员工
    
    @"employee.name ENDSWITH[c] '梦'"   //以梦结束的员工
    
    @"employee.name CONTAINS[d] '宗'"   //包含有"宗"字的员工
    
    注:[c]不区分大小写[d]不区分发音符号即没有重音符号[cd]既不区分大小写,也不区分发音符号。
    
    
    

    3、范围:IN   ,BWTEEN

    
    如:
    
    @"salary BWTEEN {5000,10000}"
    
    @"em_dept IN '开发'"
    
    
    

    4、自身:SELF,这个只针对字符数组起作用。

    
    如:
    
    NSArray * test = =[NSArray arrayWithObjects: @"guangzhou", @"beijing", @"shanghai", nil];
    
    @"SELF='beijing'"
    
    
    

    5、通配符:LIKE

    
    LIKE 使用?表示一个字符,*表示多个字符,也可以与c、d 连用。
    
    如:
    
    @"car.name LIKE '?he?'" //四个字符中,中间为he
    
    @"car.name LIKE '*jp'"   //以jp结束
   
    

    6、正则表达式:MATCHES

    
    如:
    
    NSString *regex = @"^E.+e$";//以E 开头,以e 结尾的字符。
    NSPredicate *pre= [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    if([pre evaluateWithObject: @"Employee"]){
        NSLog(@"matches YES");
        
    }else{
        NSLog(@"matches NO");
        
    }
    

    7、逻辑运算符:AND、OR、NOT

    如:
    
    @"employee.name = 'john' AND employee.age = 28"
   

    8、占位符:

    NSPredicate *preTemplate = [NSPredicate predicateWithFormat:@"name==$NAME"];
    NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:
                       @"Name1", @"NAME",nil];
    NSPredicate *pre=[preTemplate predicateWithSubstitutionVariables: dic];
    占位符就是字典对象里的key,因此你可以有多个占位符,只要key 不一样就可以了。



CoreData的操作会转换为SQL操作, 在Xcode上设置支持CoreData调试

Product-Scheme-Edit Scheme-Run-Arguments中依次添加两个参数(注意参数顺序不能错):-com.apple.CoreData.SQLDebug1。然后在运行程序过程中如果操作了数据库就会将SQL语句打印在输出面板




最后注意:CoreData线程安全问题 和CoreData的版本迁移问题, 下次有时间再整理




以上是关于iOS 数据持久化 CoreData的主要内容,如果未能解决你的问题,请参考以下文章

iOS 数据持久化 CoreData

iOS CoreData数据库之创建详解

iOS 数据持久化 CoreData的版本迁移

iOS -数据持久化方式-以真实项目讲解

swift3.0:CoreData的使用

由于 iOS 持久性商店问题和未从 Coredata 加载数据而导致应用程序崩溃