5- coreData基本使用(增删改查,干货)

Posted on Posted in iOS, 全部文章

一.文章概要

当前使用工具是XCode7.

这篇文章主要是写了对于基本数据类型的”增删改查”的操作,至于特殊类型比如UIImage,NSArray,NDDictionary我们在之后的几篇文章中讲到.

二.前话

从平常的使用来说,FMDB和coreData是项目中最经常使用的两个数据库持久化方式.

CoreData 首先它是一个 ORM框架。 SQLite 与 FMDB 其实都脱离不了关系型(relational)数据 而我们平时使用的编程语言却是面向对象的,都是对象型的。

在 iOS 中,coreData 和 FMDB 关于这两者的区别,我认为主要是如下几个方面

coreData
优点 (1)映射之后 直接操作对象就能进行增删改查 更贴近 程序员的生活。(2)我们不需要再写SQL语句,避免了 SQL语句的繁琐,比如说 SQL语句经常要写一大堆的包含 values(name,sex) 还要有对应个数的?与前边的()中的属性个数对应
缺点 (1) coreData没有 java 中的 ORM 框架快速.尤其是多表操作的时候,效率并不是很高. java中的框架(Hibernate:特点:可以把 SQL语句和面型对象的查询语句混合使用.举个例子:它可以把复杂的多表操作语句用一行查询语句来执行完毕)。而 coreData操作多表的时候,需要创建多个对应数量的Requset,description,谓词,筛选器。 (2)就单纯的批量插入数据的速度 相比较FMDB 稍微慢一点点

三.FMDB

如果你之前用过sqlSever数据库的话,继续往下看,当然你也可以直接跳过这一小节

首先,想必软件工程专业或者相关专业的同学在学校学的就是sqlSever,对应的数据库课程也是免不了的.那么sql语句是我们必须要学习的.”简单查询””多表查询”等等这些都是我们要学习的.恭喜你,你已经有了一定学习FMDB的基础了.

再进一步说,你之前从事java或者安卓开发工作的时候,用到了sqlSever,那么再次恭喜你,你基本已经可以FMDB的那些基本功能了.

由此,我们可见,FMDB的使用方式和之前在其他语言中使用sqlSever数据库的时候,是非常相似的.之前我们在使用sqlSever提到的那些关键点在FMDB中,也有体现,比如”打开数据库,关闭数据库””手敲sql语句,执行sql语句”……所以,FMDB,对于之前上手还是很熟悉,很简单的.

你到现在还没有使用过FMDB. 那也不用太烦恼和害怕,数据库的基本格式都是固定的.既然是固定的,拷贝一段改改就可以了.

扩展

(1)问:"什么时候使用coredata 什么时候使用FMDatabases?"

答: a. CoreData 在公司使用的比较少,用户的比较多的是FMDatabases。

b.数据存储的结构比较简单的时候,使用CoreData

c.CoreData 开发效率会高点,为什么?因为他是面向对象的,而且不用写sql语句. FMDatabases 数据结果比较复杂的时候,表与表之间的关联比较多的时候使用.

(2)coreData 其实底层也是要写sql 语句的,coreData 帮我们把sql语句封装。

四.你要的干货,利用coreData来持久化数据

第一步,创建’模型文件’

描述

描述

第二步,创建’实体Entity’

创建实体对象

描述 描述

创建实体对象的属性(属性名,属性类型和关联实体)

描述

问:什么是关联实体???

答:其实就是我们创建另外的一个实体.这里添加关联实体的意思就是,举个例子我们人类有个宠物狗,那么反过来宠物狗也有个主人是人类. 这里说白了就是两个对象之间的相互关联

温馨提示

描述

第三步,创建’创建NSManagedObject的子类文件’

描述

描述

描述

描述

以下的代码是系统默认生成的,这里贴出是仅供对比查验使用,在文篇文章中没有其它的意义.

创建出的子类代码-Book+CoreDataProperties.h:

#import "Book.h"

NS_ASSUME_NONNULL_BEGIN

@interface Book (CoreDataProperties)

@property (nullable, nonatomic, retain) NSNumber *bookID;
@property (nullable, nonatomic, retain) NSString *bookName;
@property (nullable, nonatomic, retain) Student *student;

@end

NS_ASSUME_NONNULL_END

创建出的子类代码-Book+CoreDataProperties.m:

#import "Book+CoreDataProperties.h"

@implementation Book (CoreDataProperties)

@dynamic bookID;
@dynamic bookName;
@dynamic student;

@end

创建出的子类代码-Book.h:

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

@class Student;

NS_ASSUME_NONNULL_BEGIN

@interface Book : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

@end

NS_ASSUME_NONNULL_END

#import "Book+CoreDataProperties.h"

创建出的子类代码-Book.m:

#import "Book.h"
#import "Student.h"

@implementation Book

// Insert code here to add functionality to your managed object subclass

@end

创建出的子类代码-Student+CoreDataProperties.h:

#import "Student.h"

NS_ASSUME_NONNULL_BEGIN

@interface Student (CoreDataProperties)

@property (nullable, nonatomic, retain) NSNumber *id;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) Book *book;

@end

NS_ASSUME_NONNULL_END

创建出的子类代码-Student+CoreDataProperties.m:

#import "Student+CoreDataProperties.h"

@implementation Student (CoreDataProperties)

@dynamic id;
@dynamic name;
@dynamic book;

@end

创建出的子类代码-Student.h:

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

@class Book;

NS_ASSUME_NONNULL_BEGIN

@interface Student : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

@end

NS_ASSUME_NONNULL_END

#import "Student+CoreDataProperties.h"

创建出的子类代码-Student.m:

#import "Student.h"
#import "Book.h"

@implementation Student

// Insert code here to add functionality to your managed object subclass

@end

第四步,创建’coreData的管理类’

我们暂时不做封装,直接在UIViewController演示.

第五步,coreData操作-创建(获取)上下文

这里的上下文在OC中,类似我们coreAnimation中用到的图形上下文. OC中哪些有上下文?

在正式看下边的'增删改查'代码之前,我们需要也别注意的是:

(0)在我们每次执行四个操作的时候,都首先要保证上下文存在(还活着)

(1)并且代码执行在'异步主队列中'

(2)'增'部分:创建保存对象部分,不是直接new或者alloc-init

(3)'查'部分:NSPredicate过滤条件(精确和非精确)

(4)'改'部分:'查'部分:NSPredicate过滤条件(精确和非精确)

(5)'删'部分:'查'部分:NSPredicate过滤条件(精确和非精确)

第六步,coreData操作-创建上下文

上边提到我们的演示文件类型是UIViewController,所以是在’viewDidLoad’方法中创建上下文,并且同时创建一个全局变量,保证上下文在我们执行’增删改查’的操作过程当中不会被销毁. 代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建上下文
    [self createCoreDataContent];
}

创建上下文的方法:

- (IBAction)createCoreDataContent{
    //创建数据库文件的路径
    //    NSString *path = [NSHomeDirectory() stringByAppendingString:@"Doucments/ImortData"];
    //    NSFileManager *manager = [NSFileManager defaultManager];
    //    if (![manager fileExistsAtPath:path]) {
    //        [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    //    }
    //

    //documet目录下
    NSString *doc  = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path = [doc stringByAppendingPathComponent:@"/student.db"];//注意不是:stringByAppendingString

    NSURL *url = [NSURL fileURLWithPath:path];
    NSLog(@"-----------------------------------");
    NSLog(@"data : %@",path);

    //创建文件,并且打开数据库文件
    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    //给存储器指定存储的类型
    NSError *error;
    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];
    context.persistentStoreCoordinator = psc;
    self.managedContext = context;
}

第七步,coreData操作-增(插入)

//插入数据
- (IBAction)insertData{
    NSLog(@"插入数据");
    //创建模型数据模型
    Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
    student.name = @"张三2";
    student.id = @(11);

    Book *book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:self.managedContext];
    book.bookID = @(121);
    book.bookName = @"<老人与海2>";

    student.book = book;

    Student *student2 = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
    student2.name = @"李四2";
    student2.id = @(23);

    Book *book2 = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:self.managedContext];
    book2.bookID = @(242);
    book2.bookName = @"<飞鸟集2>";

    student2.book = book2;

    //保存,用 save 方法
    NSError *error = nil;
    BOOL success = [self.managedContext save:&error];
    if (!success) {
        [NSException raise:@"访问数据库错误" format:@"%@",[error localizedDescription]];
    }
}

第八步,coreData操作-查

//读取数据库文件
- (IBAction)readData{
    NSLog(@"读取数据");
    dispatch_async(dispatch_get_main_queue(), ^{

        // 初始化一个查询请求
        //  NSFetchRequest *request = [[NSFetchRequest alloc] init];
        // 设置要查询的实体
        // request.entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.managedContext];

        //以上代码简写成下边
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

        // 设置排序(按照age降序)
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:NO];
        request.sortDescriptors = [NSArray arrayWithObject:sort];
        // 设置条件过滤(搜索name中包含字符串"zhang"的记录,注意:设置条件过滤时,数据库SQL语句中的%要用*来代替,所以%Itcast-1%应该写成*zhang*)
        // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*zhang*"];
        // request.predicate = predicate;

        // 执行请求
        NSError *error = nil;
        NSArray *objs = [self.managedContext executeFetchRequest:request error:&error];
        if (error) {
            [NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
        }

        NSLog(@"-----------------------------------");
        // 遍历数据
        int index = 0;
        for (NSManagedObject *obj in objs) {
            NSLog(@"%d---name=%@", index++,[obj valueForKey:@"name"]);
        }

        for (Student *stu in objs) {
            Book *book = stu.book;
            NSLog(@"%@---name=%@", stu.name,book.bookName);
        }

    });
}

第九步,coreData操作-改(更新)

//更新数据
- (IBAction)modifyData{
    // 如果是想做更新操作:只要在更改了实体对象的属性后调用[context save:&error],就能将更改的数据同步到数据库
    //先从数据库中取出所有的数据,然后从其中选出要修改的那个,进行修改,然后保存


    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

    //设置过滤条件
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@",@"李四2"];
    request.predicate = pre;

    NSError *error = nil;
    NSArray *objs = [self.managedContext executeFetchRequest:request error:&error];
    if (error) {
         [NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
    }

    // 2.更新身高
    for (Student *stu in objs) {
        stu.name = @"被修改的新名字";
    }

   //保存,用 save 方法
   BOOL success = [self.managedContext save:&error];
   if (!success) {
       [NSException raise:@"访问数据库错误" format:@"%@",[error localizedDescription]];
   }

}

第十步,coreData操作-删

//删除
- (IBAction)removeData:(id)sender{

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

    //查到到你要删除的数据库中的对象
    NSPredicate *predic = [NSPredicate predicateWithFormat:@"name = %@",@"张三2"];
    request.predicate = predic;

    //请求数据
    NSArray *objs = [self.managedContext executeFetchRequest:request error:nil];

    for (Student *stu in objs) {
        [self.managedContext deleteObject:stu];
    }

    [self.managedContext save:nil];
}

小结

为了方便地测试上边的代码,我们可以把各个方法在界面上对应.比如下图这样:

描述

到这里,对于coreData的基本操作”增删改查”的基本操作刚和代码就完成了.

具体的 Demo 代码可以在我的 GitHub 上找到
Demo地址


欢迎大家关注我的微博和我GitHub,我会不时分享和转发一些大牛的技术贴和开源项目.

新浪微博:http://weibo.com/1594425143/profile?topnav=1&wvr=6&is_all=1

GitHub:https://github.com/lilongcnc

发表评论

电子邮件地址不会被公开。 必填项已用*标注