IOS 数据存储之 Core Data

  • Core Date是ios3.0后引入的数据持久化解决方案,它是是苹果官方推荐使用的,不需要借助第三方框架。Core Date实际上是对SQLite的封装,提供了更高级的持久化方式。在对数据库操作时,不需要使用sql语句,也就意味着即使不懂sql语句,也可以操作数据库中的数据。
  • 在各类应用开发中使用数据库操作时通常都会用到 (ORM) “对象关系映射”,Core Data就是这样的一种模式。ORM是将关系数据库中的表,转化为程序中的对象,但实际上是对数据中的数据进行操作。
  • 在使用Core Data进⾏行数据库存取并不需要手动创建数据库,创建数据库的过程完全由Core Data框架自动完成,开发者需要做的就是把模型创建起来,具体数据库的创建不需要管。简单点说,Core Data实际上是将数据库的创建、表的创建、对象和表的转换等操作封装起来,极大的简化了我们的操作。
  • Core Date与SQLite相比较,SQLite比较原始,操作比较复杂,使用的是C的函数对数据库进行操作,但是SQLite可控性更强,并且能够跨平台。

下面,让我们一起来学习一下Core Data的简单使用。

一、使用Core Data,添加实体和模型

在创建项目的时候可以选择使用Core Data,项目创建成功后,会在AppDelegate类中自动添加相关代码,此外,还会自动生成一个数据模型文件*.xcdatamodeld

屏幕快照 2016-04-27 上午11.23.07.png

在AppDelegate.h文件中

//
//  AppDelegate.h
//  LSCoreDataTest
//
//  Created by a110 on 16/4/27.
//  Copyright © 2016年 a110. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@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;
- (NSURL *)applicationDocumentsDirectory;
@end

在AppDelegate.m文件中

//
//  AppDelegate.m
//  LSCoreDataTest
//
//  Created by a110 on 16/4/27.
//  Copyright © 2016年 a110. All rights reserved.
//

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    // Saves changes in the application's managed object context before the application terminates.
    [self saveContext];
}

#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 "LS.LSCoreDataTest" 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;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"LSCoreDataTest" 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]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"LSCoreDataTest.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();
        }
    }
}

@end

以上代码是自动生成的。

如果项目在创建的时候没有选择使用Core Data,但是在后面需要使用,那么需要手动的添加AppDelegate中的相关代码。此外,还需要手动添加一个Data Model文件

屏幕快照 2016-04-27 上午11.27.02.png
  • 创建Data Model文件时需要注意,文件名称要与AppDelegate.m中managedObjectModel方法中提到的文件名称相匹配。

有了Data Model文件后,就可以在里面添加实体和关系,实际上就是向数据库中添加表格和建立表格之间的关联。添加实体如图所示:

0534CAFC-FC06-47F8-89FC-C599EB3CD4D7.png

每个学生有一个所在的班级,每个班级中有多个学生,因此,学生和班级之间可以建立关系。建立关系如图所示:

10EA2031-7395-41EF-B45C-70E6397647B4.png
FA627D67-E5E9-4498-915C-54C546B76A2D.png

建立关系之后,可以切换显示的样式,以图表的方式查看实体之间的关系,如图所示:

DAE5FCF5-F7D4-49B0-A445-97F9CBCCCA78.png

完成上述步骤,数据库中表格的创建就已经完成,和使用SQLite比较,省略了sql语句以及调用C函数操作数据库的步骤,另外,在创建实体的时候不需要设置主键,实体对象的属性的类型是OC的类型,实体中其他实体对象类型是通过建立关系添加的。
  创建好实体后,可以通过添加NSManagedObject subclass文件,系统可以自动添加实体对应的数据模型类,如图所示:

屏幕快照 2016-04-27 上午11.46.06.png
屏幕快照 2016-04-27 上午11.46.42.png
屏幕快照 2016-04-27 上午11.46.53.png
屏幕快照 2016-04-27 上午11.50.16.png

二、通过代码实现数据库操作

1、 向学生表中插入一条数据

在使用Core Data的时候,AppDelegate中添加了NSManagedObjectContext对象,需要获得这个管理对象的上下文来进行操作。在操作的过程中,需要得到NSManagedObject实体,然后通过kvc设置实体的属性值,最后通过上下文调用save方法保存数据。

- (void)insert {
    
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    
    //1. 获得context
    NSManagedObjectContext *context = delegate.managedObjectContext;
    //2. 找到实体结构,并生成一个实体对象
    /*
     NSEntityDescription实体描述,也就是表的结构
     参数1:表名字
     参数2:实例化的对象由谁来管理,就是context
     */
    NSManagedObject *class1 = [NSEntityDescription insertNewObjectForEntityForName:@"Classes" inManagedObjectContext:context];
    [class1 setValue:[NSNumber numberWithInt:1] forKey:@"c_id"];
    [class1 setValue:@"一班" forKey:@"c_name"];
    for (int i= 0 ; i<10; i++) {
        NSManagedObject *stu = [NSEntityDescription insertNewObjectForEntityForName:@"Students" inManagedObjectContext:context];
        
        
        
        //3. 设置实体属性值
        [stu setValue:[NSNumber numberWithInt:i+11] forKey:@"s_id"];
        [stu setValue:@"jerehedu" forKey:@"s_name"];
        [stu setValue:class1 forKey:@"s_class"];

        
        //4. 调用context,保存实体,如果没有成功,返回错误信息
        NSError *error;
        if ([context save:&error]) {
            NSLog(@"save ok");
        }
        else
        {
            NSLog(@"%@",error);
        }

    }
}

2、查询学生表中全部数据

查询与插入数据操作类似,但是多了构造查询对象的步骤,查询得到结果集是一个数组,遍历数组,可以取出查询数据。

- (void)selectAll {
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    
    NSManagedObjectContext *context = delegate.managedObjectContext;
    
    NSEntityDescription *stu = [NSEntityDescription entityForName:@"Students" inManagedObjectContext:context];
    
    //构造查询对象
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:stu];
    
//    //构造查询条件,相当于where子句
//    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"s_id=%i",12];
//    //把查询条件放进去
//    [request setPredicate:predicate];

    
//    //按降序查询
//    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"s_id" ascending:NO];
//    [request setSortDescriptors:[NSArray arrayWithObject:sort]];
    
//    ///分页查询
//    [request setFetchLimit:2];
//    [request setFetchOffset:2 * 2];
    
    
    ///按区间查询
     NSPredicate * qcondition= [NSPredicate predicateWithFormat:@"s_id >= 15"];
    [request setPredicate:qcondition];
    
    
    //执行查询,返回结果集
    NSArray *resultAry = [context executeFetchRequest:request error:nil];
    
    //遍历结果集
    for (NSManagedObject *enity in resultAry) {
        NSLog(@"id=%i name=%@ class=%@",[[enity valueForKey:@"s_id"] intValue],[enity valueForKey:@"s_name"],[[enity valueForKey:@"s_class"] valueForKey:@"c_name"]);
    }
    
}

3、查询指定条件的学生信息,并更新

指定条件的查询除了需要构造查询对象,还需要把查询的条件用谓词表示。然后遍历查询结果数组中的数据,进行更行,并保存。

- (void)update
{
    //    更新 (从数据库找到-->更新)
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = delegate.managedObjectContext;
    
    NSEntityDescription *stu = [NSEntityDescription entityForName:@"Students" inManagedObjectContext:context];
    
    NSFetchRequest *request = [NSFetchRequest new];
    [request setEntity:stu];
    
    //构造查询条件,相当于where子句
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"s_id=%i",12];
    //把查询条件放进去
    [request setPredicate:predicate];
    
    //执行查询
    NSArray *studentAry = [context executeFetchRequest:request error:nil];
    if (studentAry.count>0)
    {
        for (int i = 0; i<studentAry.count; i++) {
            //更新里面的值
            NSManagedObject *obj = studentAry[i];
            [obj setValue:@"apple" forKey:@"s_name"];
        }
        
    }
    ///如果不执行save方法的话,程序重新启动时还是初始数据
    [context save:nil];
    [self selectAll];
}
4、删除指定条件的学生信息

删除之前首先需要根据条件进行查询,查询到数据后删除,并保存。

- (void)delete
{
    //删除 先找到,然后删除
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = delegate.managedObjectContext;
    
    NSEntityDescription *stu = [NSEntityDescription entityForName:@"Students" inManagedObjectContext:context];
    
    NSFetchRequest *request = [NSFetchRequest new];
    [request setEntity:stu];
    
    //构造查询条件,相当于where子句
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"s_id=%i",19];
    
    //把查询条件放进去
    [request setPredicate:predicate];
    //执行查询
    NSManagedObject *obj = [[context executeFetchRequest:request error:nil] lastObject];
    //删除
    if (obj) {
        [context deleteObject:obj];
        [context save:nil];
    }
    
    [self selectAll];
}

三、小结

Core Data是苹果官方推荐使用的数据持久化方式,在使用的过程中,不需要导入数据库框架,也不需要使用sql语句操作数据库,完全是按照面向对象的思想,使用实体模型来操作数据库。在使用的过程中需要注意的是,如果模型发生了变化,可以选择重新生成实体类文件,但是自动生成的数据库并不会自动更新,需要考虑重新生成数据库,并把之前数据库中数据进行移植。Core Data能够简化操作,但是它不支持跨平台使用,如果想实现跨平台,就需要使用SQLite来进行数据持久化。

四、另:CoreData条件查询之NSPredicate应用

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

NSPredicate 中支持的关键词和条件符:

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

如:
NSPredicate * qcondition= [NSPredicate predicateWithFormat:@"s_id >= 15"];

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

如:
@"s_name BEGINSWITH[cd] 'apple'" //姓apple的学生
@"s_name ENDSWITH[c] 'apple'" //以apple结束的学生
@"s_name CONTAINS[d] 'apple'" //包含有"apple"字的学生
注:[c]不区分大小写[d]不区分发音符号即没有重音符号[cd]既不区分大小写,也不区分发音符号。

3、范围:IN ,BWTEEN

如:
@"s_id BWTEEN {5,10}"
@"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 不一样就可以了。

ios Coredata 关联 UITableView 数据自动更新

ios Coredata 关联 UITableView 数据自动更新

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • iOS数据存储之Core Data(一) Core Data 基础 Core Data 是一个API集合,被设计用...
    comst阅读 958评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,103评论 18 139
  • iOS数据存储 1. 概论 在iOS开发中数据存储的方式可以归纳为两类: 存储文件 和 存储到数据库. 2.文件存...
    ValienZh阅读 736评论 0 1
  • 第十六天…… 这几天总是有些犯懒,今天白天插空写了两段,刚才停下来的时候才发现竟然没保存。“还是先洗个澡吧!哎!算...
    豆宝妈妈阅读 171评论 0 0
  • 时光飞逝,转眼间孩子们已经入营四天。通过四天紧张充实的军营生活,小营员们已经蜕变成一名合格的特种兵小战士。他们在成...
    君临天下紫龙阅读 431评论 1 1