CC 許可,轉(zhuǎn)載請(qǐng)注明出處
Core data 是 Cocoa 中處理數(shù)據(jù),綁定數(shù)據(jù)的關(guān)鍵特性,其重要性不言而喻,但也比較復(fù)雜。Core Data 相關(guān)的類比較多,初學(xué)者往往不太容易弄懂。計(jì)劃用三個(gè)教程來講解這一部分:
框架詳解:講解 Core data 框架,運(yùn)作過程,設(shè)計(jì)的類;
Core data應(yīng)用程序示例:通過生成一個(gè)使用 Core data 的應(yīng)用程序來講解如何 在 XCode 4 中使用 Core data。
手動(dòng)創(chuàng)建Core data示例:不利用框架自動(dòng)生成代碼,完全自己編寫所有的 Core data 相關(guān)代碼的命令行應(yīng)用程序來深入講解 Core data的使用。
本文為第一部份:框架詳解
一,概觀
下面先給出一張類關(guān)系圖,讓我們對(duì)它有個(gè)總體的認(rèn)識(shí)。
在上圖中,我們可以看到有五個(gè)相關(guān)模塊:
1, Managed Object Model
Managed Object Model 是描述應(yīng)用程序的數(shù)據(jù)模型,這個(gè)模型包含實(shí)體(Entity),特性(Property),讀取請(qǐng)求(Fetch Request)等。(下文都使用英文術(shù)語。)
2,Managed Object Context
Managed Object Context 參與對(duì)數(shù)據(jù)對(duì)象進(jìn)行各種操作的全過程,并監(jiān)測(cè)數(shù)據(jù)對(duì)象的變化,以提供對(duì) undo/redo 的支持及更新綁定到數(shù)據(jù)的 UI。
3,Persistent Store Coordinator
Persistent Store Coordinator 相當(dāng)于數(shù)據(jù)文件管理器,處理底層的對(duì)數(shù)據(jù)文件的讀取與寫入。一般我們無需與它打交道。
4,Managed Object
Managed Object 數(shù)據(jù)對(duì)象,與 Managed Object Context 相關(guān)聯(lián)。
5,Controller
圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器,一般都是通過 control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數(shù)據(jù)。
這寫模塊是怎樣運(yùn)作的呢?
1,應(yīng)用程序先創(chuàng)建或讀取模型文件(后綴為xcdatamodeld)生成 NSManagedObjectModel 對(duì)象。Document應(yīng)用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(后綴為 xcdatamodeld)讀取。
2,然后生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對(duì)象,前者對(duì)用戶透明地調(diào)用后者對(duì)數(shù)據(jù)文件進(jìn)行讀寫。
3,NSPersistentStoreCoordinator 負(fù)責(zé)從數(shù)據(jù)文件(xml, sqlite,二進(jìn)制文件等)中讀取數(shù)據(jù)生成 Managed Object,或保存 Managed Object 寫入數(shù)據(jù)文件。
4,NSManagedObjectContext 參與對(duì)數(shù)據(jù)進(jìn)行各種操作的整個(gè)過程,它持有 Managed Object。我們通過它來監(jiān)測(cè) Managed Object。監(jiān)測(cè)數(shù)據(jù)對(duì)象有兩個(gè)作用:支持 undo/redo 以及數(shù)據(jù)綁定。這個(gè)類是最常被用到的。
5,Array Controller, Object Controller, Tree Controller 這些控制器一般與 NSManagedObjectContext 關(guān)聯(lián),因此我們可以通過它們?cè)?nib 中可視化地操作數(shù)據(jù)對(duì)象。
二, Model class
模型有點(diǎn)像數(shù)據(jù)庫(kù)的表結(jié)構(gòu),里面包含 Entry, 實(shí)體又包含三種 Property:Attribute(屬性),RelationShip(關(guān)系), Fetched Property(讀取屬性)。Model class 的名字多以 "Description" 結(jié)尾。我們可以看出:模型就是描述數(shù)據(jù)類型以及其關(guān)系的。
主要的 Model class 有:
Managed Object Model | NSManagedObjectModel | 數(shù)據(jù)模型 |
Entity | NSEntityDescription | 抽象數(shù)據(jù)類型,相當(dāng)于數(shù)據(jù)庫(kù)中的表 |
Property | NSPropertyDescription | Entity 特性,相當(dāng)于數(shù)據(jù)庫(kù)表中的一列 |
> Attribute | NSAttributeDescription | 基本數(shù)值型屬性(如Int16, BOOL, Date等類型的屬性) |
> Relationship | NSRelationshipDescription | 屬性之間的關(guān)系 |
> Fetched Property | NSFetchedPropertyDescription | 查詢屬性(相當(dāng)于數(shù)據(jù)庫(kù)中的查詢語句) |
1)Entity - NSEntityDescription
Entity 相當(dāng)于數(shù)據(jù)庫(kù)中的一個(gè)表,它描述一種抽象數(shù)據(jù)類型,其對(duì)應(yīng)的類為 NSManagedObject 或其子類。
NSEntityDescription 常用方法:
+insertNewObjectForEntityForName:inManagedObjectContext: 工廠方法,根據(jù)給定的 Entity 描述,生成相應(yīng)的 NSManagedObject 對(duì)象,并插入 ManagedObjectContext 中。
-managedObjectClassName 返回映射到 Entity 的 NSManagedObject 類名
-attributesByName 以名字為 key, 返回 Entity 中對(duì)應(yīng)的 Attributes
-relationshipsByName 以名字為 key, 返回 Entity 中對(duì)應(yīng)的 Relationships
2)Property - NSPropertyDescription
Property 為 Entity 的特性,它相當(dāng)于數(shù)據(jù)庫(kù)表中的一列,或者 XML 文件中的 value-key 對(duì)中的 key。它可以描述實(shí)體數(shù)據(jù)(Attribute),Entity之間的關(guān)系(RelationShip),或查詢屬性(Fetched Property)。
> Attribute - NSAttributeDescription
Attribute 存儲(chǔ)基本數(shù)據(jù),如 NSString, NSNumber or NSDate 等。它可以有默認(rèn)值,也可以使用正則表達(dá)式或其他條件對(duì)其值進(jìn)行限定。一個(gè)屬性可以是 optional 的。
> Relationship - NSRelationshipDescription
Relationship 描述 Entity,Property 之間的關(guān)系,可以是一對(duì)一,也可以是一對(duì)多的關(guān)系。
> Fetched Property - NSFetchedPropertyDescription
Fetched Property 根據(jù)查詢謂詞返回指定 Entity 的符合條件的數(shù)據(jù)對(duì)象。
上面說的比較抽象,舉個(gè)例子來說,見圖:
我們有一個(gè) CocoaDataDemo.xcdatamodeld 模型文件,應(yīng)用程序根據(jù)它生成一個(gè) NSManagedObjectModel 對(duì)象,這個(gè)模型有三個(gè) Entity,每個(gè) Entity 又可包含 Attribute Relationship, Feteched Property 三種類型的 Property。在本例中, Author Entity 包含兩個(gè)Attribute : name 和 email,它們對(duì)于的運(yùn)行時(shí)類均為 NSManagedObject;還包含一個(gè)與 Post 的 Relationship;沒有設(shè)置 Feteched Property。
我們通常使用 KVC 機(jī)制來訪問 Property。下面來看代碼:
NSManagedObjectContext * context = [[NSApp delegate] managedObjectContext]; NSManagedObject * author = nil; author = [NSEntityDescription insertNewObjectForEntityForName: @"Author" inManagedObjectContext: context]; [author setValue: @"nemo@pixar.com" forKey: @"email"]; NSLog (@"The Author's email is: %@", [author valueForKey:@"email"]);
在上面代碼中,我們先取得 NSManagedObjectContext, 然后調(diào)用 NSEntityDescription 的方法,以 Author 為實(shí)體模型,生成對(duì)應(yīng)的 NSManagedObject 對(duì)象,插入 NSManagedObjectContext 中,然后給這個(gè)對(duì)象設(shè)置特性 email 的值。
三,運(yùn)行時(shí)類與對(duì)象
> Managed Object - NSManagedObject
Managed Object 表示數(shù)據(jù)文件中的一條記錄,每一個(gè) Managed Object 在內(nèi)存中對(duì)應(yīng) Entity 的一個(gè)數(shù)據(jù)表示。Managed Object 的成員為 Entity 的 Property 所描述。
比如在上面的代碼,author 這個(gè) NSManagedObject,對(duì)應(yīng)名為 Author 的 Entity。
每一個(gè) Managed Object 都有一個(gè)全局 ID(類型為:NSManagedObjectID)。Managed Object 會(huì)附加到一個(gè) Managed Object Context,我們可以通過這個(gè)全局 ID 在 Managed Object Context 查詢對(duì)應(yīng)的 Managed Object。
-entity | 獲取其 Entity |
-objectID | 獲取其 Managed Object ID |
-valueForKey: | 獲取指定 Property 的值 |
-setValue: forKey: | 設(shè)定指定 Property 的值 |
> Managed Object Context - NSManagedObjectContext
Managed Object Context 的作用相當(dāng)重要,對(duì)數(shù)據(jù)對(duì)象進(jìn)行的操作都與它有關(guān)。當(dāng)創(chuàng)建一個(gè)數(shù)據(jù)對(duì)象并插入 Managed Object Context 中,Managed Object Context 就開始跟蹤這個(gè)數(shù)據(jù)對(duì)象的一切變動(dòng),并在合適的時(shí)候提供對(duì) undo/redo 的支持,或調(diào)用 Persistent Store Coordinato 將變化保存到數(shù)據(jù)文件中去。
通常我們將 controller 類(如:NSArrayController,NSTreeController)或其子類與 Managed Object Context 綁定,這樣就方便我們動(dòng)態(tài)地生成,獲取數(shù)據(jù)對(duì)象等。
-save: | 將數(shù)據(jù)對(duì)象保存到數(shù)據(jù)文件 |
-objectWithID: | 查詢指定 Managed Object ID 的數(shù)據(jù)對(duì)象 |
-deleteObject: | 將一個(gè)數(shù)據(jù)對(duì)象標(biāo)記為刪除,但是要等到 Context 提交更改時(shí)才真正刪除數(shù)據(jù)對(duì)象 |
-undo | 回滾最后一步操作,這是都 undo/redo 的支持 |
-lock | 加鎖,常用于多線程以及創(chuàng)建事務(wù)。同類接口還有:-unlock and -tryLock |
-rollback | 還原數(shù)據(jù)文件內(nèi)容 |
-reset | 清除緩存的 Managed Objects。只應(yīng)當(dāng)在添加或刪除 Persistent Stores 時(shí)使用 |
-undoManager | 返回當(dāng)前 Context 所使用的 NSUndoManager |
-assignObject: toPersistantStore: | 由于 Context 可以管理從不同數(shù)據(jù)文件而來的數(shù)據(jù)對(duì)象, 這個(gè)接口的作用就是指定數(shù)據(jù)對(duì)象的存儲(chǔ)數(shù)據(jù)文件(通過指定 PersistantStore 實(shí)現(xiàn)) |
-executeFetchRequest: error: | 執(zhí)行 Fetch Request 并返回所有匹配的數(shù)據(jù)對(duì)象 |
> Persistent Store Coordinator - NSPersistentStoreCoordinator
使用 Core Data document 類型的應(yīng)用程序,通常會(huì)從磁盤上的數(shù)據(jù)文中中讀取或存儲(chǔ)數(shù)據(jù),這寫底層的讀寫就由 Persistent Store Coordinator 來處理。一般我們無需與它直接打交道來讀寫文件,Managed Object Context 在背后已經(jīng)為我們調(diào)用 Persistent Store Coordinator 做了這部分工作。
-addPersistentStoreForURL:configuration:URL:options:error: | 裝載數(shù)據(jù)存儲(chǔ),對(duì)應(yīng)的卸載數(shù)據(jù)存儲(chǔ)的接口為 -removePersistentStore:error: |
-migratePersistentStore:toURL:options:withType:error: | 遷移數(shù)據(jù)存儲(chǔ),效果與 "save as"相似,但是操作成功后, 遷移前的數(shù)據(jù)存儲(chǔ)不可再使用 |
-managedObjectIDForURIRepresentation: | 返回給定 URL所指示的數(shù)據(jù)存儲(chǔ)的 object id,如果找不到匹配的數(shù)據(jù)存儲(chǔ)則返回 nil |
-persistentStoreForURL: | 返回指定路徑的 Persistent Store |
-URLForPersistentStore: | 返回指定 Persistent Store 的存儲(chǔ)路徑 |
> Persistent Document - NSPersistentDocument
NSPersistentDocument 是 NSDocument 的子類。 multi-document Core Data 應(yīng)用程序使用它來簡(jiǎn)化對(duì) Core Data 的操作。通常使用 NSPersistentDocument 的默認(rèn)實(shí)現(xiàn)就足夠了,它從 Info.plist 中讀取 Document types 信息來決定數(shù)據(jù)的存儲(chǔ)格式(xml,sqlite, binary)。
-managedObjectContext | 返回文檔的 Managed Object Context,在多文檔應(yīng)用程序中,每個(gè)文檔都有自己的 Context。 |
-managedObjectModel | 返回文檔的 Managed Object Model |
四,F(xiàn)etch Requests
Fetch Requests 相當(dāng)于一個(gè)查詢語句,你必須指定要查詢的 Entity。我們通過 Fetch Requests 向 Managed Object Context 查詢符合條件的數(shù)據(jù)對(duì)象,以 NSArray 形式返回查詢結(jié)果,如果我們沒有設(shè)置任何查詢條件,則返回該 Entity 的所有數(shù)據(jù)對(duì)象。我們可以使用謂詞來設(shè)置查詢條件,通常會(huì)將常用的 Fetch Requests 保存到 dictionary 以重復(fù)利用。
示例:
NSManagedObjectContext * context = [[NSApp delegate] managedObjectContext]; NSManagedObjectModel * model = [[NSApp delegate] managedObjectModel]; NSDictionary * entities = [model entitiesByName]; NSEntityDescription * entity = [entities valueForKey:@"Post"]; NSPredicate * predicate; predicate = [NSPredicate predicateWithFormat:@"creationDate > %@", date]; NSSortDescriptor * sort = [[NSortDescriptor alloc] initWithKey:@"title"]; NSArray * sortDescriptors = [NSArray arrayWithObject: sort]; NSFetchRequest * fetch = [[NSFetchRequest alloc] init]; [fetch setEntity: entity]; [fetch setPredicate: predicate]; [fetch setSortDescriptors: sortDescriptors]; NSArray * results = [context executeFetchRequest:fetch error:nil]; [sort release]; [fetch release];
在上面代碼中,我們查詢?cè)谥付ㄈ掌谥髣?chuàng)建的 post,并將查詢結(jié)果按照 title 排序返回。
-setEntity: | 設(shè)置你要查詢的數(shù)據(jù)對(duì)象的類型(Entity) |
-setPredicate: | 設(shè)置查詢條件 |
-setFetchLimit: | 設(shè)置最大查詢對(duì)象數(shù)目 |
-setSortDescriptors: | 設(shè)置查詢結(jié)果的排序方法 |
-setAffectedStores: | 設(shè)置可以在哪些數(shù)據(jù)存儲(chǔ)中查詢 |
參考資料:
Core Data Reference API listing for the Core Data classes
http://developer.apple.com/documentation/Cocoa/Reference/CoreData_ObjC/index.html
NSPredicate Reference API listing for NSPredicate
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSPredicate.html