IOS開發之——Core Data學習

Core data 是 Cocoa 中處理數據,綁定數據的關鍵特性,其重要性不言而喻,但也比較複雜。Core Data相關的類比較多,初學者往往不太容易弄懂。我近期花了一週多時間,才基本入門,今天將一些要點整理出來分享:

一、Core Data 框架的概述

Core Data 是 Cocoa 裏面一套非常受歡迎的框架,從 Mac OS X 10.4 提供以來,在 10.5 中引入了完善的schema 遷移機制,再到 iPhone OS 3.0 時被引入 Cocoa Touch,這套完善的框架都被認爲是管理大量結構化數據所首選的 Cocoa 框架,尤其是因爲使用 Core Data 能大大減少需要手工編寫的代碼量,就使它更受開發者歡迎了。

不過最近卻出現了一些不同的聲音,先是傳出消息說 Aperture 3.0 拋棄了 Core Data ,改爲直接操作 SQLite數據庫 (大家聯想到 Apple Mail 3.0 也是直接用 SQLite,沒有用 Core Data),但因爲都是 Apple 內部的決定,大家只能憑空猜測理由;接下來,NetNewsWire 的開發者 Brent Simmons 也說在 NetNewsWire for iPhone 裏從 Core Data 轉向用 FMDB 來操作 SQLite 數據庫 (FMDB 是 Gus Mueller 編寫的一層很薄的 SQLite 在 Objective-C 下的封裝)Brent 給的理由就很充分了:他要做的很多操作都是對數據批量進行的,其實不需要把所有數據都保存在內存裏遍歷執行,那樣更慢,直接交給數據庫,往往一條語句就搞定了,簡潔而且快速。

然後 Jonathan “Wolf” Rentzsch 也對此深表贊同 ,並推薦 Aaron Hillegass 的 BNRPersistence 框架,這個框架用Tokyo Cabinet 提供了一個類似 Core Data 接口的數據持久化方案,最大的優點是比 Core Data 快得多,根據Aaron 自己的測試,常見的操作都要快 10 - 20 倍。其實快這麼多也可以理解,畢竟 BNRPersistence 要比 Core Data 輕量得多,支持的功能也少很多,加上 Tokyo Cabinet 這樣的 Key-value 數據庫在處理適合它的操作時,多數要比 SQLite 這樣的關係型數據庫要快。

所以突然 Core Data 就有點被牆倒衆人推的意思,好像以前大家都知道它不好用,但都不好意思說,直到突然有經驗足夠豐富的開發者開頭,就一涌而上開始罵了。我個人的觀感是 Core Data 作爲官方方案,給開發提供的許多便利還是不可小視的,但考慮學起來確實也不容易 (所以纔有人專門寫本書講 Core Data ),所以新上手的Cocoa 程序員不妨先考慮一下 BNRPersistence, FMDB 這樣的方案。

那是否 Core Data 就該被拋棄呢?目前的爭議其實有點像 Web 開發裏到底該不該用 ORM , 區別是大多數Web 開發者因爲歷史原因,對直接進行數據庫操作有偏好 (或者說,本能地反感 ORM),而多數 Cocoa 開發者則堅定支持用對象操作數據,所以長遠來看,數據持久化方案在 Cocoa (Touch) 開發裏少不了,唯一的疑問是 Apple會不會繼續改進 Core Data 的性能和接口,以拉近與第三方方案的差距,只要 Apple 還在不斷改進,Core Data 就有學習的必要。

我個人對 Core Data 的怨念主要是在要寫的“膠水代碼”上:有的時候爲了方便與界面的 bindings 操作,不得不給 Model 寫大量重複的膠水代碼,所以如果第三方的方案如果在這方面有簡化,我很樂意改用。

 

二、Core DataSQLite數據庫

並非嚴格的說, CoreData是對SQLite數據庫的一個封裝。

在蘋果iPhoneiPad上,你可以存放數據在以下三個地方

其一是:一個或多個文件

其二是:應用的屬性列表(NSUserDefaults

其三是:內置的數據庫(SQLite

通常SQLite數據庫操作的基本流程是, 創建數據庫, 再通過定義一些字段來定義表格結構, 可以利用sql語句向表格中插入記錄, 刪除記錄, 修改記錄, 表格之間也可以建立聯繫。

這個過程出現了, 表格的結構(schema), 所有表格的結構和相互聯繫構成整個數據庫的模型, 數據庫存放的方式(可以是文件或者在內存), 數據庫操作, sql語句(主要是查詢), 表格裏面的記錄,下面將上面說的文字,CoreData的類作個對應:

SQLite數據庫操作

VS

CoreData的類

表格結構

-->

NSEntityDescription

數據庫中所有表格和他們的聯繫

-->

NSManagedObjectModel

數據庫存放方式

-->

NSPersistentStoreCoordinator

數據庫操作

-->

NSManagedObjectContext

查詢語句

-->

NSFetchRequest

表格的記錄

-->

NSManagedObject

可能上面的對應關係並非十分嚴格, 但確實可以幫助理解. 

下面再看看CoreData的類

首先是NSEntityDescriptionNSManagedObjectModel這兩個非常重要的類

NSEntityDescription用來定義表格結構,所以你就可以理解NSManagedObjectModel中的setEntities:(NSArray *)entities函數大概有什麼用了,通常, 定義model,是用文件CoreData.xcdatamodel, 可以圖形化的操作. 這類似用nib來創建界面。

例如:建個工程, 使用core  data, 模擬器運行之後, 程序對應的document目錄出現一個CoreData.sqlite. 可以利用sqlite3命令來查看裏面的表格結構:

用命令行sqlite3 CoreData.sqlite 進入

>.tables

ZEVENT        Z_METADATA    Z_PRIMARYKEY

可以看到有表格ZEVENT, 對應的CoreData.xcdatamodel文件有名字叫EventEntity

 

>.schema ZEVENT

CREATE TABLE ZEVENT ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZTIMESTAMP TIMESTAMP )

對應的Event中有屬性timeStamp, 可以看到, 相應的ZEVENT表格中有字段TIMESTAMP

 

> select * from ZEVENT

1|1|1|306295807.974966

2|1|1|306295810.981875

3|1|1|306295811.982537

這表格有三個記錄, 可以用來初始化三個NSManagedObject, 修改了NSManagedObject, save之後也修改了表格記錄。

你可以在CoreData.xcdatamodel添加新的entity, 之後用sqlit3命令來查看數據庫的變化。

三、深入認識Core Data 框架

下面先給出一張類關係圖,讓我們對它有個總體的認識。


在上圖中,我們可以看到有五個相關模塊:

    1、被管理對象模型(Managed Object Models)

    Managed Object Model 是描述應用程序的數據模型,這個模型包含實體(Entity),特性(Property),讀取請求(Fetch Request)等。多數Core Data的功能依賴於你創建的,用來描述程序的實體及其屬性、關係的模型圖。

    2、被管理對象和上下文(Managed Objects and Contexts)

Managed Object Context 參與對數據對象進行各種操作的全過程,並監測數據對象的變化,以提供對undo/redo 的支持及更新綁定到數據的 UI。使用Core Data的框架,大多數的功能都可以自動實現,因爲我們有managed object context(管理對象的上下文,有時直接叫"Context")。managed object context就像是一個關卡,通過它可以訪問框架底層的對象——這些對象的集合我們稱之爲"persistence stack"(數據持久棧)。 managed object context作爲程序中對象和外部的數據存儲的中轉站。棧的底部是persistence object stores(持久化數據存儲)

    3、持久化存儲助理(Persistent Store Coordinator)

Persistent Store Coordinator 相當於數據文件管理器,處理底層的對數據文件的讀取與寫入。一般我們無需與它打交道。之前提到過,程序中的對象和外部存儲的數據通過Core Data框架中的一系列對象進行協調,這一系列的對象總的被稱爲持久存儲棧(Persistence stack)。在棧頂是被管理對象上下文(Managed object context),而棧底是持久化對象存儲層(Persistence object store)。在它們之間就是持久化存儲助理。

    4、數據對象(Managed Object ——MO)

    Managed Object 數據對象,與 Managed Object Context 相關聯。

    5、控制器Controller

    圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器,一般都是通過control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數據。

這些模塊是怎樣運作的呢?

1、應用程序先創建或讀取模型文件(後綴爲xcdatamodeld)生成 NSManagedObjectModel 對象。Document應用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(後綴爲xcdatamodeld)讀取。

2、然後生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對象,前者對用戶透明地調用後者對數據文件進行讀寫。

3NSPersistentStoreCoordinator 負責從數據文件(xml, sqlite,二進制文件等)中讀取數據生成 Managed Object,或保存 Managed Object 寫入數據文件。

4NSManagedObjectContext 參與對數據進行各種操作的整個過程,它持有 Managed Object。我們通過它來監測 Managed Object。監測數據對象有兩個作用:支持 undo/redo 以及數據綁定。這個類是最常被用到的。

5Array Controller, Object Controller, Tree Controller 這些控制器一般與NSManagedObjectContext 關聯,因此我們可以通過它們在 nib 中可視化地操作數據對象。

四、Model class

模型有點像數據庫的表結構,裏面包含 Entry, 實體又包含三種 PropertyAttribute(屬性),RelationShip(關係), Fetched Property(讀取屬性)。Model class 的名字多以 "Description" 結尾。我們可以看出:模型就是描述數據類型以及其關係的。

主要的 Model class 有:

Model Classes

Managed Object Model

NSManagedObjectModel

數據模型

Entity

NSEntityDescription

抽象數據類型,相當於數據庫中的

Property

NSPropertyDescription

Entity 特性,相當於數據庫表中的一列

  > Attribute

NSAttributeDescription

基本數值型屬性(如Int16, BOOL, Date等類型的屬性)

  > Relationship

NSRelationshipDescription

屬性之間的關係

  > Fetched Property

NSFetchedPropertyDescription

查詢屬性(相當於數據庫中的查詢語句)

 

1Entity - NSEntityDescription

Entity 相當於數據庫中的一個表,它描述一種抽象數據類型,其對應的類爲 NSManagedObject 或其子類。

NSEntityDescription 常用方法:

+insertNewObjectForEntityForName:inManagedObjectContext: //工廠方法,根據給定的 Entity 描述,生成相應的 NSManagedObject 對象,並插入 ManagedObjectContext 中。

-managedObjectClassName //返回映射到 Entity 的 NSManagedObject 類名

-attributesByName //以名字爲 key, 返回 Entity 中對應的 Attributes

-relationshipsByName //以名字爲 key, 返回 Entity 中對應的 Relationships

 

2Property – NSPropertyDescription

Property 爲 Entity 的特性,它相當於數據庫表中的一列,或者 XML 文件中的 value-key 對中的 key。它可以描述實體數據屬性(Attribute)Entity之間的關係(RelationShip),或查詢屬性(Fetched Property)

 

 > Attribute - NSAttributeDescription

Attribute 存儲基本數據,如 NSString, NSNumber or NSDate 等。它可以有默認值,也可以使用正則表達式或其他條件對其值進行限定。一個屬性可以是 optional 的。

 

 > Relationship - NSRelationshipDescriptio

Relationship 描述 EntityProperty 之間的關係,可以是一對一,也可以是一對多的關係。 

 

 > Fetched Property - NSFetchedPropertyDescription

Fetched Property 根據查詢謂詞返回指定 Entity 的符合條件的數據對象。

上面說的比較抽象,舉個例子來說,見圖:

   我們有一個 CocoaDataDemo.xcdatamodeld 模型文件,應用程序根據它生成一個 NSManagedObjectModel對象,這個模型有三個 Entity,每個 Entity 又可包含 Attribute 、RelationshipFeteched Property 三種類型的 Property。在本例中, Author Entity 包含兩個Attribute : name 和 email,它們對於的運行時類均爲 NSManagedObject;還包含一個與 Post 的 Relationship;沒有設置Feteched Property訪問屬性。

我們通常使用 KVC 機制來訪問 Property。下面來看代碼:

[代碼]c#/cpp/oc代碼:

1 NSManagedObjectContext * context = [[NSApp delegate] managedObjectContext]; 
2 NSManagedObject        * author  = nil; 
3        
4 author = [NSEntityDescription insertNewObjectForEntityForName: @"Author" inManagedObjectContext: context]; 
5 [author setValue: @"[email protected]" forKey: @"email"]; 
6  
7 NSLog (@"The Author's email is: %@", [author valueForKey:@"email"]);

 在上面代碼中,我們先取得 NSManagedObjectContext,然後調用 NSEntityDescription 的方法,以 Author 爲實體模型,生成對應的 NSManagedObject 對象,插入 NSManagedObjectContext 中,然後給這個對象設置特性 email的值。

    五、運行時——類與對象

> Managed Object – NSManagedObject

Managed Object 表示數據文件中的一條記錄,每一個 Managed Object 在內存中對應 Entity 的一個數據表示。Managed Object 的成員爲 Entity 的 Property 所描述。

比如在上面的代碼,author 這個 NSManagedObject,對應名爲 Author 的 Entity

 

每一個 Managed Object 都有一個全局 ID(類型爲:NSManagedObjectID)。Managed Object 會附加到一個Managed Object Context,我們可以通過這個全局 ID 在 Managed Object Context 查詢對應的 Managed Object

NSManagedObject 常用方法

-entity

獲取其 Entity

-objectID

獲取其 Managed Object ID

-valueForKey:

獲取指定 Property 的值

-setValue: forKey:

設定指定 Property 的值

> Managed Object Context – NSManagedObjectContext

Managed Object Context 作用相當重要,對數據對象進行的操作都與它有關。當創建一個數據對象並插入Managed Object Context 中,Managed Object Context 就開始跟蹤這個數據對象的一切變動,並在合適的時候提供對 undo/redo 的支持,或調用 Persistent Store Coordinato 將變化保存到數據文件中去。

通常我們將 controller 類(如:NSArrayControllerNSTreeController)或其子類 Managed Object Context 綁定,(如何綁定?後有介紹)這樣就方便我們動態地生成,獲取數據對象等。

NSManagedObjectContext 常用方法

-save:

將數據對象保存到數據文件

-objectWithID:

查詢指定 Managed Object ID 的數據對象

-deleteObject:

將一個數據對象標記爲刪除,但是要等到 Context 提交更改時才真正刪除數據對象

-undo

回滾最後一步操作,這是對undo/redo 的支持

-lock

加鎖,常用於多線程以及創建事務。同類接口還有:-unlock and -tryLock

-rollback

還原數據文件內容

-reset

清除緩存的 Managed Objects。只應當在添加或刪除 Persistent Stores 時使用

-undoManager

返回當前 Context 所使用的 NSUndoManager

-assignObject: toPersistantStore:

由於 Context 可以管理從不同數據文件而來的數據對象,這個接口的作用就是指定數據對象的存儲數據文件(通過指定 PersistantStore 實現)

-executeFetchRequest: error:

執行 Fetch Request 並返回所有匹配的數據對象

 

> Persistent Store Coordinator - NSPersistentStoreCoordinator

使用 Core Data document 類型的應用程序,通常會從磁盤上的數據文中中讀取或存儲數據,這寫底層的讀寫就由 Persistent Store Coordinator 來處理。一般我們無需與它直接打交道來讀寫文件,Managed Object Context 在背後已經爲我們調用 Persistent Store Coordinator 做了這部分工作。

NSPersistentStoreCoordinator 常用方法

-addPersistentStoreForURL:configuration:URL:options:error:

裝載數據存儲,對應的卸載數據存儲的接口爲 -removePersistentStore:error:

-migratePersistentStore:toURL:options:withType:error:

遷移數據存儲,效果與 "save as"相似,但是操作成功後,遷移前的數據存儲不可再使用

-managedObjectIDForURIRepresentation:

返回給定 URL所指示的數據存儲的 object id,如果找不到匹配的數據存儲則返回 nil

-persistentStoreForURL:

返回指定路徑的 Persistent Store

-URLForPersistentStore:

返回指定 Persistent Store 的存儲路徑

 

> Persistent Document - NSPersistentDocument

NSPersistentDocument 是 NSDocument 的子類。 multi-document Core Data 應用程序使用它來簡化對Core Data 的操作。通常使用 NSPersistentDocument 的默認實現就足夠了,它從 Info.plist 中讀取Document types 信息來決定數據的存儲格式(xml,sqlite, binary)。

NSPersistentDocument 常用方法

-managedObjectContext

返回文檔的 Managed Object Context,在多文檔應用程序中,每個文檔都有自己的 Context

-managedObjectModel

返回文檔的 Managed Object Model

 

   六、Fetch Requests

Fetch Requests 相當於一個查詢語句,你必須指定要查詢的 Entity。我們通過 Fetch Requests 向Managed Object Context 查詢符合條件的數據對象,以 NSArray 形式返回查詢結果,如果我們沒有設置任何查詢條件,則返回該 Entity 的所有數據對象。我們可以使用謂詞來設置查詢條件,通常會將常用的 Fetch Requests 保存到 dictionary 以重複利用。

NSFetchRequest 常用方法

-setEntity:

設置你要查詢的數據對象的類型(Entity

-setPredicate:

設置查詢條件

-setFetchLimit:

設置最大查詢對象數目

-setSortDescriptors:

設置查詢結果的排序方法

-setAffectedStores:

設置可以在哪些數據存儲中查詢


[代碼]c#/cpp/oc代碼:

01 NSManagedObjectContext * context  = [[NSApp delegate] managedObjectContext]; 
02 NSManagedObjectModel   * model    = [[NSApp delegate] managedObjectModel]; 
03 NSDictionary           * entities = [model entitiesByName]; 
04 NSEntityDescription    * entity   = [entities valueForKey:@"Post"]; 
05     
06 NSPredicate * predicate; 
07 predicate = [NSPredicate predicateWithFormat:@"creationDate > %@", date]; 
08   
09 NSSortDescriptor * sort = [[NSortDescriptor alloc] initWithKey:@"title"]; 
10 NSArray * sortDescriptors = [NSArray arrayWithObject: sort]; 
11   
12 NSFetchRequest * fetch = [[NSFetchRequest alloc] init]; 
13 [fetch setEntity: entity]; //設置你要查詢的數據對象的類型(Entity)
14 [fetch setPredicate: predicate]; //設置查詢條件
15 [fetch setSortDescriptors: sortDescriptors]; // 設置查詢結果的排序方法
16    
17 NSArray * results = [context executeFetchRequest:fetch error:nil]; 
18 [sort release]; 
19 [fetch release];

    在上面代碼中,我們查詢在指定日期之後創建的 post,並將查詢結果按照 title 排序返回。

 

參考資料:

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


原貼地址:http://www.devdiv.com/iPhone開發學習筆記——Core_Data_框架及運作過程和設計的類-weblog-228548-49362.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章