前言:
學習了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
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
具體使用方式
//清空資料 [[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 的資料模型升級相容性比較差,如果模型不對,會導致程式連起都起不來。雖然提供了模型升級程式碼,但是在客戶端的管理模型版本管理也會相對複雜。