引言:
Core Data 是 iOS 3.0 以後引入的資料持久化解決方案,其原理是對SQLite的封裝,是開發人員不需要接觸SQL語句,就可以對資料庫進行的操作.
其編碼方式和原理結構方面較為特殊,本博文主要介紹在使用Core Data時遇到的各種問題以及對其核心原理進行解釋.
參考資料:
1: iOS教程:Core Data資料持久性儲存基礎教程
http://www.dasheyin.com/ios_jiao_cheng_core_data_shu_ju_chi_jiu_xing_cun_chu_ji_chu_jiao_cheng.html
安裝:
安裝的方式只有一步,引入CoreData.framework 即可.
使用:
使用Core Data起步最先要瞭解和熟悉的類是以下三個:
1:NSManagedObjectModel
2:NSPersistentStoreCoordinator
3:NSManagedObjectContext
在此也特別的說明一下,如果你沒有理解透這三個類分別是做什麼的,那麼往後看到的代碼都有一種非常迷茫的感覺:
接下來分別介紹每一個類的具體功能和用途:
1.NSManagedObjectModel(管理物件模型,以下簡稱:上下文):
構建整個資料庫的表結構,表欄位類型,表與表之間的關係(Relationship)等等凡是和資料結構有關的定義都通過此類來管理.
那麼使用此類需要一個Data Model(資料模型)檔案來配合其一起使用,如所示建立出來:
那麼我們所有資料結構的定義和設計都用這個Data Model來完成.
在代碼方面需要通過檔案路徑的方式找到它,並初始化NSManagedObjectModel
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Data Model Name" withExtension:@"momd"];self.keyManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
注:建立Data Model檔案以後的副檔名稱是: Data Model Name.xcdatamodeld但通過XCode編譯打包成App以後,其會被轉換成一個Data
Model Name.momd檔案.而我們真正要加的模型檔案就是這個Data Model Name.momd檔案.
2.NSPersistentStoreCoordinator(持久性資料協調器):
NSPersistentStoreCoordinator是真正意義上和SQLite打交道的類,主要根據NSManagedObjectModel 執行表結構的建立,通過NSManagedObjectContext 的命令執行資料互動
.
self.keyPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: self.keyManagedObjectModel];// handle db upgradeNSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];if (![self.keyPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]){}
注:通過NSManagedObjectModel初始化,一旦初始化成功,SQLite的DB,就已經有了完善的表結構關係,不過這不是我們關心的重點,繼續往下.
3.NSManagedObjectContext(管理物件內容)
NSManagedObjectContext是我們在開發中主要互動的類,資料的增刪改查都通過上下文去觸發命令並返回結果. 根據一個NSPersistentStoreCoordinator 完成初始化
self.keyManagedObjectContext = [[NSManagedObjectContext alloc] init];[self.keyManagedObjectContext setPersistentStoreCoordinator:self.keyPersistentStoreCoordinator];
到此,CoreData的準備工作已經完成,其實XCode已經有模版可以直接完成CoreData的準備工作,不過對於新手來說,最好還是一步一步來,加以理解,以便出現BUG時,能夠及時找到解決方案,貴在理解!
接下來,開始操縱資料!
插入一條?更新一條?刪除一條?
熟悉Sql語句的同學:腦子裡立刻會想到:insert into table , update table , delete table
那麼在CoreData,這三項工作全部通過save函數來完成,一個函數完成三件事,CoreData這麼犀利的?
NSPredicate(條件適配器)
NSPredicate主要為NSFetchRequest而服務,提供查詢時的各種條件陳述式,方面過濾出複合業務需求的資料.
以下先列出 NSPredicate 支援的萬用字元
1:相等(==) 舉例: field == 'value'
2:不相等(!=) 舉例: field != 'value'
3:模糊(like) 舉例: field like '*value*' 或者 field like '?value?' like 使用?表示一個字元,*表示多個字元
4:比較( > < <= >= ) 舉例: field > 6
以上4種萬用字元都是字串直接拼接即可,接下來的萬用字元在拼接字串方面較為麻煩,但有相關代碼可以輔助拼接.
5:範圍(between) 舉例: field between {"6", "10"}
可以通過如下代碼拼接條件命令:
NSArray *range = [[NSArray alloc]initWithObjects:@"6",@"10",nil];NSPredicate *betweenPredicate =[NSPredicate predicateWithFormat:@"field between %@", range];NSLog(@"%@",betweenPredicate.predicateFormat);
6:包含(in) 舉例: filed IN {"value1", "value2"}
可以通過如下代碼拼接條件命令:
NSArray *choice = [[NSArray alloc]initWithObjects:@"value1",@"value2",nil];NSPredicate *inPredicate =[NSPredicate predicateWithFormat:@"filed in %@", choice];NSLog(@"%@",inPredicate.predicateFormat);
7:複合(or and not) 舉例: filed == "value2" OR filed == "value3"
也可以通過如下代碼拼接:
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"filed == 'value1' "];NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"filed == 'value2' "];NSArray *predicates = [[NSArray alloc]initWithObjects:predicate1,predicate2,nil];NSPredicate *andCompoundPredicate =[NSCompoundPredicate orPredicateWithSubpredicates:predicates];
在調用save 函數時我需要注意些什麼?
一個對象只屬於一個上下文對象,所以不同上下文管轄的對象不允許用一個上下文來調用save 方法,這隻會失敗,錯誤提示如下:
Illegal attempt to establish a relationship 'xyz' between objects in different contexts
解決辦法是(參考:StackOverflow):
NSManagedObject *book = // get a book in one MOCNSManagedObject *owner = // get an owner in a different MOC[[owner mutableSetValueForKey:@"books"] addObject:[owner managedObjectContext:objectWithID:[book objectID]]];
Persistent Store Coordinator (持久性資料協調器): 你可以將這個東西看作是資料庫連接庫,在這裡,你將設定資料存放區的名字和位置,以及資料存放區的時機。
Managed Object Context (管理資料內容):你可以將這一部分看作是資料的實際內容,這也是整個資料庫中對我們而言最重要的部分(這還用說),基本上,插入資料,查詢資料,刪除資料的工作都在這裡完成。
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:entity];[request setResultType:NSManagedObjectIDResultType];
[request setFetchBatchSize:20];
NSError* error = nil;
NSArray* items = [context executeFetchRequest:request error:&error];
for (NSManagedObjectID* objectID in items) {
NSManagedObject* object = [context objectWithID:objectID];
...}
countForFetchRequest:error
1:表與表之間關係建立教程http://blog.csdn.net/fengsh998/article/details/8123392
2:針對應用升級和表結構變動時 相容舊版本的CoreData資料庫解決辦法.遇到的問題:當你將CoreData 加入到工程中,並啟動了App一切都運行良好,可是開發途中修改了CoreData 的 資料結構,比如添加或者刪除了某個欄位,或者新添加了一張表.此時,再運行App時,發現App直接Crash.如何解決:這說明CoreData無法做到時時的去修改表結構,但CoreData可以以多個副本的形式來處理資料結構變化時的Crash問題.闡述一下原理: 原理類似SVN 需要打一個 tag 一樣, 一擔打了Tag 就意味著這個版本的代碼將不再允許修改,如果需要修改,需要到新的分枝裡去實現.當利用開發工具建立CoreData 管理檔案以後:FEMicroCoopModel.xcdatamodeld 預設是只有一個分枝的.那麼添加分枝方式如下:1.IDE->Editor->Add Model Version...2.之後顯示如下介面:兩個欄位:Version name:版本名稱(按你所需來取)Based on model:基本模型(這裡選擇一個,已經有的分枝,繼承的概念)Finish之後就完成了,那麼新的資料結構修改,都請在這個檔案上面進行操作.當你修改的差不多以後,需要設定 CoreData管理檔案的 (Versioned Core Data Model) 當前使用版本,如:只有這樣應用運行時才會按照新版資料結構去遷移資料和修改表結構.代碼方面只有兩個地方需要注意一下:1:添加對資料結構版本自適應的配置,代碼如下:
// handle db upgradeNSDictionary *options =[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,nil];
2:在執行個體化 NSManagedObjectModel 對象 需要傳入模型名稱,這裡只要是你當初建立 CoreData管理對象時的名稱即可.3:讓控制台擁有輸出 Core Data執行的SQL語句的能力.為Edit Scheme - Run - Arguments - 添加一項值:
-com.apple.CoreData.SQLDebug 1
如所示:
3:警告和錯誤1:has no children 警告提示如:解決方案:將圖中的勾勾去掉 編譯即可
總結: