• IOS数据存储之CoreData使用优缺点


    前言:

       学习了Sqlite数据之后认真思考了一下,对于已经习惯使用orm数据库的开发者或者对sql语句小白的开发者来说该如何做好数据库开发呢?这个上网搜了一下?看来总李多虑了!apple 提供了一种数据方式,它就是今天的主角:CoreData!我们一起来探究它是否能够满足我们项目开发的需要呢?

    CoreData介绍:

       Core Date是ios3.0后引入的数据持久化解决方案,它是是苹果官方推荐使用的,不需要借助第三方框架。Core Date实际上是对SQLite的封装,提供了更高级的持久化方式。在对数据库操作时,不需要使用sql语句,也就意味着即使不懂sql语句,也可以操作数据库中的数据。

    CoreData优点:

        Core Data实际上是将数据库的创建、表的创建、对象和表的转换等操作封装起来,极大的简化了我们的操作。Core Date与SQLite相比较,SQLite比较原始,操作比较复杂,使用的是C的函数对数据库进行操作,但是SQLite可控性更强,并且能够跨平台。

    CoreData缺点:

          存储性能一般,默认建立的表没有主键,效率低,复杂的查询更是不敢想像。CoreData 对批量数据的处理执行的不太好,查资料好像说IOS8推出了批量处理的一些方式。对于多线程的支持也不太好,我是xcode 7上开发的每一个entity都要生成4个类,打个比方一个项目中要建10个表那就要维护40个类,你说累不累?

    怎么使用CoreData?

       第一步:在项目中引入CoreData.framework

        第二步:创建xxxx.xcdatamodeld

         第三步:模型对象的实体

    接下来就是具体实现:具体实现之前先来认识如下几个对象

    (1)NSManagedObjectModel(被管理的对象模型)

               相当于实体,不过它包含 了实体间的关系

      (2)NSManagedObjectContext(被管理的对象上下文)

             操作实际内容

            作用:插入数据  查询  更新  删除

     (3)NSPersistentStoreCoordinator(持久化存储助理)

              相当于数据库的连接器

       (4)NSFetchRequest(获取数据的请求)    

            相当于查询语句

       (5)NSPredicate(相当于查询条件)

       (6)NSEntityDescription(实体结构)

    为了方便实现,本文整理一个数据管理类来测试CoreData:CoreDataManager

    CoreDataManager.h

    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    @interface CoreDataManager : NSObject<NSCopying>
    
    @property(strong,nonatomic,readonly)NSManagedObjectModel* managedObjectModel;//管理数据模型
    
    @property(strong,nonatomic,readonly)NSManagedObjectContext* managedObjectContext;//管理数据内容
    
    @property(strong,nonatomic,readonly)NSPersistentStoreCoordinator* persistentStoreCoordinator;//持久化数据助理
    
    //创建数据库管理者单例
    +(instancetype)shareManager;
    
    //插入数据
    -(void)insertData:(NSString*)tempName;
    
    //删除数据
    -(void)deleteData;
    
    //删除数据
    -(void)deleteData:(NSString*)tempName;
    
    //查询数据
    -(void)queryData;
    
    //根据条件查询
    -(void)queryData:(NSString*)tempName;
    
    //更新数据
    -(void)updateData:(NSString*)tempName;
    
    @end
    View Code

    CoreDataManager.m

    #import "CoreDataManager.h"
    #import "Car.h"
    
    static CoreDataManager *shareManager=nil;
    
    @implementation CoreDataManager
    
    @synthesize managedObjectContext =_managedObjectContext;
    
    @synthesize managedObjectModel = _managedObjectModel;
    
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
    
    //实例化对象
    -(instancetype)init
    {
        self=[super init];
        if (self) {
            
        }
        return self;
    }
    
    //创建数据库管理者单例
    +(instancetype)shareManager
    {
        //这里用到了双重锁定检查
        if(shareManager==nil){
            @synchronized(self){
                if(shareManager==nil){
                    shareManager =[[[self class]alloc]init];
                }
            }
        }
        return shareManager;
    }
    
    -(id)copyWithZone:(NSZone *)zone
    {
        
        return shareManager;
    }
    
    +(id)allocWithZone:(struct _NSZone *)zone
    {
        if(shareManager==nil){
            shareManager =[super allocWithZone:zone];
        }
        return shareManager;
    }
    
    //托管对象
    -(NSManagedObjectModel *)managedObjectModel
    {
        if (_managedObjectModel!=nil) {
            return _managedObjectModel;
        }
        
        NSURL* modelURL=[[NSBundle mainBundle] URLForResource:@"myCoreData" withExtension:@"momd"];
        _managedObjectModel=[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return _managedObjectModel;
    }
    
    //托管对象上下文
    -(NSManagedObjectContext *)managedObjectContext
    {
        if (_managedObjectContext!=nil) {
            return _managedObjectContext;
        }
        
        NSPersistentStoreCoordinator* coordinator=[self persistentStoreCoordinator];
        if (coordinator!=nil) {
            _managedObjectContext=[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];//NSMainQueueConcurrencyType NSPrivateQueueConcurrencyType
            
            [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
        return _managedObjectContext;
    }
    
    //持久化存储协调器
    -(NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if (_persistentStoreCoordinator!=nil) {
            return _persistentStoreCoordinator;
        }
        NSString* docs=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
        NSURL* storeURL=[NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@"myCoreData.sqlite"]];
        NSLog(@"path is %@",storeURL);
        NSError* error=nil;
        _persistentStoreCoordinator=[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
            NSLog(@"Error: %@,%@",error,[error userInfo]);
        }
        return _persistentStoreCoordinator;
    }
    
    //插入数据
    -(void)insertData:(NSString*)tempName
    {
        //读取类
        Car *car=[NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        car.name=tempName;
        //保存
        NSError *error;
        [self.managedObjectContext save:&error];
    }
    
    //删除数据
    -(void)deleteData
    {
        //创建读取类
        NSEntityDescription *entity =[NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        
        //创建连接
        NSFetchRequest* request=[[NSFetchRequest alloc] init];
        [request setEntity:entity];
        
        //启动查询
        NSError *error;
        NSArray *deleteArr=[self.managedObjectContext executeFetchRequest:request error:&error];
        if(deleteArr.count){
            for (Car *car in deleteArr) {
                [self.managedObjectContext deleteObject:car];
            }
            NSError *error;
            [self.managedObjectContext save:&error];
        }else{
            NSLog(@"未查询到可以删除的数据");
        }
    
    }
    
    //删除数据
    -(void)deleteData:(NSString*)tempName;
    {
        //创建读取类
        NSEntityDescription *entity =[NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        
        //创建连接
        NSFetchRequest* request=[[NSFetchRequest alloc] init];
        [request setEntity:entity];
        
        //创建检索条件
        NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name=%@",tempName];
        [request setPredicate:predicate];
        
        //启动查询
        NSError *error;
        NSArray *deleteArr=[self.managedObjectContext executeFetchRequest:request error:&error];
        if(deleteArr.count){
            for (Car *car in deleteArr) {
                [self.managedObjectContext deleteObject:car];
            }
             NSError *error;
            [self.managedObjectContext save:&error];
        }else{
            NSLog(@"未查询到可以删除的数据");
        }
    }
    
    
    //查询数据
    -(void)queryData
    {
        //创建读取类
        NSEntityDescription *entity =[NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        
        //创建连接
        NSFetchRequest* request=[[NSFetchRequest alloc] init];
        [request setEntity:entity];
        
        //启动查询
        NSError *error;
        NSArray *carArr=[self.managedObjectContext executeFetchRequest:request error:&error];
        for(Car *car in carArr){
            NSLog(@"car---->%@",car.name);
        }
        
    }
    
    -(void)queryData:(NSString*)tempName
    {
        //创建读取类
        NSEntityDescription *entity =[NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        
        //创建连接
        NSFetchRequest* request=[[NSFetchRequest alloc] init];
        [request setEntity:entity];
        
        //创建检索条件
        NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name=%@",tempName];
        [request setPredicate:predicate];
        
        //启动查询
        NSError *error;
        NSArray *carArr=[self.managedObjectContext executeFetchRequest:request error:&error];
        for(Car *car in carArr){
            NSLog(@"car---->%@",car.name);
        }
        
    }
    
    //更新数据
    -(void)updateData:(NSString*)tempName
    {
        //创建读取类
        NSEntityDescription *entity =[NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        
        //创建连接
        NSFetchRequest* request=[[NSFetchRequest alloc] init];
        [request setEntity:entity];
        
        //创建检索条件
        NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name=%@",tempName];
        [request setPredicate:predicate];
        
        //启动查询
        NSError *error;
        NSArray *deleteArr=[self.managedObjectContext executeFetchRequest:request error:&error];
        if(deleteArr.count){
            for (Car *car in deleteArr) {
                car.name=@"test";
            }
            NSError *error;
            [self.managedObjectContext save:&error];
        }else{
            NSLog(@"未查询到可以删除的数据");
        }
    
    }
    
    @end
    View Code

     具体使用方式

        //清空数据
               [[CoreDataManager shareManager]deleteData];
               //插入10条数据
               for(int i=0;i<10;i++){
                   NSString *string = [[NSString alloc] initWithFormat:@"%d",i];
                   [[CoreDataManager shareManager]insertData:string];
               }
               //然后查询一下
                [[CoreDataManager shareManager]queryData];
               //然后删除一条数据
                [[CoreDataManager shareManager]deleteData:@"5"];
               //然后查询一下
               [[CoreDataManager shareManager]queryData];
               // 更新数据
               [[CoreDataManager shareManager]updateData:@"3"];
               //然后查询一下
               [[CoreDataManager shareManager]queryData];
               
               //清空数据
               [[CoreDataManager shareManager]deleteData];
               
               //然后查询一下
               [[CoreDataManager shareManager]queryData];
               

    测试一下效率:测试数据10000条

     NSMutableArray *testArray =[[NSMutableArray alloc]init];
               int testMaxCount =10000;
               for(int i=0;i<testMaxCount;i++){
                   NSString *string = [[NSString alloc] initWithFormat:@"%d",i];
                  [testArray addObject:string];
               }
               
                //测试一下效率  第1种
               CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
               for(NSString *tempName in testArray){
                    [[CoreDataManager shareManager]insertData:tempName];
               }
               CFAbsoluteTime end=CFAbsoluteTimeGetCurrent();
               NSLog(@"coreData数据插入 time cost: %0.3f", end - start);
               
               //测试一下效率  第2种
                 start = CFAbsoluteTimeGetCurrent();
                [[CoreDataManager shareManager]insertDatas:testArray];
                 end=CFAbsoluteTimeGetCurrent();
                NSLog(@"coreData数据插入 time cost: %0.3f", end - start);
    insertData函数:
    //插入数据
    -(void)insertData:(NSString*)tempName
    {
        //读取类
        Car *car=[NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
        car.name=tempName;
        //保存
        NSError *error;
        [self.managedObjectContext save:&error];
    }
    insertDatas函数:
    //插入数据
    -(void)insertDatas:(NSArray*)tempNames
    {
        for(NSString *name in tempNames){
            Car *car=[NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
            car.name=name;
        }
        NSError *error;
        [self.managedObjectContext save:&error];
        
    }

    运行结果:

    第一种:8.408

    第二种:0.162

    但是有个超级大的问题,第二种方式虽然效率高,但是插入数据乱序。第一种正常但是效率超低,同样近似的数据量sqlite效率比这个高不知多少倍。如果用这个来做数据库开发我觉得是无爱了。批量操作支持的不太好。对于它的数据库升级也不想过多了解。所以就随便查了下,得出如下结论:CoreData 的数据模型升级兼容性比较差,如果模型不对,会导致程序连起都起不来。虽然提供了模型升级代码,但是在客户端的管理模型版本管理也会相对复杂。

  • 相关阅读:
    Linux发行版 CentOS6.5 修改默认主机名
    《Linux就该这么学》培训笔记_ch06_存储结构与磁盘划分
    《Linux就该这么学》培训笔记_ch05_用户身份与文件权限
    《Linux就该这么学》培训笔记_ch04_Vim编辑器与Shell命令脚本
    《Linux就该这么学》培训笔记_ch03_管道符、重定向与环境变量
    《Linux就该这么学》培训笔记_ch02_一些必须掌握的Linux命令
    《Linux就该这么学》培训笔记_ch01_部署虚拟环境安装Linux系统
    《Linux就该这么学》培训笔记_ch00_认识Linux系统和红帽认证
    Swift笔记2
    request对象和response对象
  • 原文地址:https://www.cnblogs.com/whoislcj/p/5488024.html
Copyright © 2020-2023  润新知