iOS 通過CoreData實現數據持久化引言:
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
安裝:
安裝的方式只有1步,引入
CoreData.framework
便可.
使用:
使用 Core Data 起步最早要了解和熟習的類是以下3個:1:NSManagedObjectModel2:NSPersistentStoreCoordinator3:NSManagedObjectContext
在此也特別的說明1下,如果你沒有理解透這3個類分別是做甚么的,那末往后看到的代碼都有1種非常迷茫的感覺:
接下來分別介紹每個類的具體功能和用處:1.NSManagedObjectModel(管理對象模型,以下簡稱:上下文):
構建全部數據庫的表結構,表字段類型,表與表之間的關系(Relationship)等等凡是和數據結構有關的定義都通過此類來管理.
那末使用此類需要1個 Data Model(數據模型)文件來配合其1起使用,以下圖所示新建出來:
那末我們所有數據結構的定義和設計都用這個 Data Model 來完成.在代碼方面需要通過文件路徑的方式找到它,并初始化 NSManagedObjectModel[csharp] view plaincopy
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Data Model Name" withExtension:@"momd"];
self.keyManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
注:新建Data Model文件以后的文件擴大名稱是: Data ModelName.xcdatamodeld但通過XCode編譯打包成App以后,其會被轉換成1個Data ModelName.momd文件.而我們真正要加的模型文件就是這個Data Model Name.momd文件.
2.NSPersistentStoreCoordinator(持久性數據調和器):
NSPersistentStoreCoordinator 是真正意義上和 SQLite 打交道的類,主要根據NSManagedObjectModel 履行表結構的建立,通過 NSManagedObjectContext 的命令履行數據交互.
[csharp] view plaincopy
1. self.keyPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: self.keyManagedObjectModel];
2.
3.4.5.
6.
7.8.
// handle db upgrade
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
yOption,tion,
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticall
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOp
nil];
if (![self.keyPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{}
9.注:通過NSManagedObjectModel初始化,1旦初始化成功,SQLite的DB,就已有了完善的表結構
關系,不過這不是我們關心的重點,繼續往下.3.NSManagedObjectContext(管理對象上下文)
NSManagedObjectContext 是我們在開發中主要交互的類,數據的增刪改查都通過上下文去觸發命令并返回結果. 根據1個 NSPersistentStoreCoordinator 完成初始化
[csharp] view plaincopy
self.keyManagedObjectContext = [[NSManagedObjectContext alloc] init];
[self.keyManagedObjectContext setPersistentStoreCoordinator:self.keyPersistentStoreCoordi
nator];
到此,CoreData的準備工作已完成,其實XCode已有模版可以直接完成CoreData的準備工作,不過對新手來講,最好還是1步1步來,加以理解,以便出現BUG時,能夠及時找到解決方案,貴在理解!
接下來,開始操縱數據!
插入1條?更新1條?刪除1條?
熟習 Sql
語句的同學:頭腦里立刻會想到:insert
into table , update table , delete table
那末在 CoreData,這3項工作全部通過 save 函數來完成,1個函數完成3件事,CoreData 這么鋒利的?
NSPredicate(條件適配器)
NSPredicate
主要為 NSFetchRequest
而服務,提供查詢時的各種條件語句,方面過濾出復合業務需
求的數據.
以下先列出 NSPredicate 支持的通配符
1:相等(==) 舉例: field == 'value'
2:不相等(!=) 舉例: field != 'value'
3:模糊(like) 舉例: field like '*value*' 或 field like '?value?' like 使用?表示1個字符,*表示多個字符
4:比較(><<=>=)
舉例: field>6
以上 4
種通配符都是字符串直接拼接便可,接下來的通配符在拼接字符串方面較為麻煩,但有相干
代碼可以輔助拼接.
5:范圍(between)
舉例: field between {"6", "10"}可以通過以下代碼拼接條件命令:
[csharp]
view plaincopy
NSArray *range = [[NSArray alloc]initWithObjects:@"6",@"10",nil];
NSPredicate *betweenPredicate =[NSPredicate predicateWithFormat:@"field between %@",
range];
NSLog(@"%@",betweenPredicate.predicateFormat);
6:包括(in)
舉例: filed IN {"value1", "value2"}可以通過以下代碼拼接條件命令:
[csharp]
view plaincopy
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"
也能夠通過以下代碼拼接:[csharp] view plaincopy
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"filed == 'value1' "];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"filed == 'value2' "];
NSArray *predicates = [[NSArray alloc]initWithObjects:predicate1,predicate2,nil];
NSPredicate *andCompoundPredicate =[NSCompoundPredicate orPredicateWithSubpredicat
es:predicates];
在調用 save 函數時我需要注意些甚么?1個對象只屬于1個上下文對象,所以不同上下文管轄的對象不允許用1個上下文來調用 save
方法,這只會失敗,毛病提示以下:
Illegal attempt to establish a relationship 'xyz' between objects in different contexts解決辦法是(參考:StackOverflow):
[csharp]
view plaincopy
NSManagedObject *book = // get a book in one MOC
NSManagedObject *owner = // get an owner in a different MOC
[[owner mutableSetV alueForKey:@"books"] addObject:[owner managedObjectContext:objec
tWithID:[book objectID]]];
Persistent Store Coordinator
(持久性數據調和器): 你可以將這個東西看做是數據庫連接庫,在這里,你將設置數據存儲的名字和位置,和數據存儲的時機。
Managed Object Context
(管理數據內容):你可以將這1部份看做是數據的實際內容,這也是全部數據庫中對我們而言最重要的部份(這還用說),基本上,插入數據,查詢數據,刪除數據的工作都在這里完成。
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
加入到工程中,并啟動了App1切都運行良好,
可是開發途中修改了CoreData
的 數據結構,比如添加或刪除某個字段,或新添加了1張表.此時,再運行App時,發現App直接Crash.
如何解決:這說明CoreData沒法做到時時的去修改表結構,但CoreData可以以多個副本的情勢來處理數據結構變化時的Crash問題.
論述1下原理:
原理類似SVN
需要打1個
tag 1樣,
1擔打了Tag就意味著這個版本的代碼將不再允許修改,如果需要修改,需要到新的分枝里去實現.當利用開發工具新建CoreData
管理文件以后:FEMicroCoopModel.xcdatamodeld默許是只有1個分枝的.
那末添加分枝方式以下:
1.IDE->Editor->Add Model Version...
2.以后顯示以下界面:
兩個字段:
Version name:版本名稱(按你所需來取)
Based on model:基礎模型(這里選擇1個,已有的分枝,繼承的概念)
Finish以后就完成了,那末新的數據結構修改,都請在這個文件上面進行操作.
當你修改的差不多以后,需要設置 CoreData管理文件的 (Versioned Core Data Model)當前使用版本,以下圖:
只有這樣利用運行時才會依照新版數據結構去遷移數據和修改表結構.
代碼方面只有兩個地方需要注意1下:1:添加對數據結構版本自適應的配置,代碼以下:[csharp] view plaincopy
// handle db upgrade
NSDictionary *options =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
2:在實例化 NSManagedObjectModel 對象 需要傳入模型名稱,這里只要是你當初建立CoreData管理對象時的名稱便可.
3:讓控制臺具有輸出 Core Data履行的SQL語句的能力.為Edit Scheme - Run - Arguments - 添加1項值:[csharp] view plaincopy
1. -com.apple.CoreData.SQLDebug 1
以下圖所示:
3:正告和錯誤1:has no children正告提示以下圖:
解決方法:
將圖中的勾勾去掉 編譯便可