詳解持久化Core Data框架的原理以及使用---轉自Bison的技術博客

1.原理部分

Core Data是一個純粹的面向對象框架,可用于管理實體以及實體之間的關聯關系的持久化,也就是我們通常所指的數據持久化。
Core Data底層的持久化存儲方式可以是SQLite數據庫,也可以是XML文檔,甚至可以直接以內存作為持久化存儲設備。
Core Data的核心概念是實體。實體是由Core Data管理的模型對象,它必須是NSManagedObject類或其子類的實例。實體與實體之間存在1-1、1-N、N-N、的關聯關系,整個應用的所有實體以及實體之間的關聯關系被稱為托管對象模型NSManagedObiectModel
Core Data的核心對象是托管對象上下文NSManagedObjectContext,所有實體都處于托管對象上下文管理中,Core Data應用對實體所做的任何增、刪、查、改操作都必須通過托管對象上下文來完成。
開發者開發的應用程序需要通過NSMannagedObjectContext對實體進行增、刪、查、改操作,而NSMannagedObjectContext底層與持久化存儲協調銜接,持久化存儲協調器則負責管理底層的存儲形式比如:SQLite
Core Data應用中的核心API有如下幾個。

托管對象模型NSManagedObiectModel:該對象負責管理整個應用的所有實體以及實體之間的關聯關系。當開發者使用Xcode的圖形界面設計了實體與實體的關聯關系之后,需要使用該對象來加載、管理應用的托管對象模型。


持久化存儲協調器NSPeristentStoreCoordinator:負責管理底層的存儲文件,例如SQLite數據庫等。


托管對象上下文NSManagedObjectContext:該對象是Core Data的核心對象,應用對實體所做的任何增、刪、查、改操作都必須通過該對象來完成。


實體描述NSEntityDescription:該對象代表了關于某個實體的描述信息,從某種程度來說,該對象相當于實體的抽象。實體描述定義了該實體的名字、實體的實現類,并用一個集合定義了該實體包含的所有屬性。


抓取請求NSFetchRequest:該對象封裝了查詢實體的請求,包括程序需要查詢哪些實體、查詢條件、排序規則等。抓取請求定義了本次查詢的實體的名字、抓取請求的查詢條件,通過NSPredicate來表示,并用一個NSArray集合定義了所有的排序規則。


熟悉以上幾點之后,使用Core Data持久化操作的步驟大致如下。

  • 創建NSManagedObiectModel對象來加載管理應用的托管對象模型。
  • NSManagedObiectModel對象為基礎,根據實際需要創建NSPeristentStoreCoordinator對象,該對象確定Core Data底層數據的存儲形式。
  • NSManagedObiectModel對象為基礎,創建NSMannagedObjectContext,該對象是Core Data進行持久化訪問的核心對象。
  • 對于普通的增、刪、查、改操作,需要分別先創建實體、刪除實體、修改實體,然后調用NSMannagedObjectContext對象的save:方法將這些修改保存到底層存儲設備。
  • 如果要執行查詢,則需要先創建NSFetchRequest對象,再調用NSMannagedObjectContextexecuteFetchRequest:error:方法執行查詢,該方法返回所有匹配條件的實體組成的NSArray

2.手動配置環境

iOS允許在創建項目時勾選“Use Core Data”復選框,通過該方式創建的項目已經完成了所有Core Data必須資源的初始化,但此處并不打算使用這種方式來初始化Core Data項目,而是選擇從一個Empty Application開始,手動初始化Core Data項目,這樣便于大家真正理解Core Data項目需要初始化哪些資源。
下面我們將開始把這個Empty Application項目一步步改造成Core Data項目。
具體步驟如下:

  • 為該項目添加CoreData.framework框架。

  • 為該項目添加一個實體模型文件。單擊Xcode主菜單的"File"--->"New"--->"File"菜單項,具體如下圖:


    coreData01.png
  • AppDelegate中初始化Core Data應用必須的核心API對象:NSManagedObiectModelNSPeristentStoreCoordinatorNSManagedObjectContext修改應用程序委托類的接口部分,在接口部分定義上面3個核心API的屬性,并增加一個對NSManagedObjectContext對象執行存儲的方法、一個獲取應用Docouments目錄下的方法。下面是修改后的接口部分代碼。

AppDelegate.h

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
// 定義Core Data的3個核心API的屬性
@property (readonly, strong, nonatomic) NSManagedObjectContext*
managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator*
persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end

接下來在AppDelegate.m中實現部分進行修改,初始化對象,并實現saveContext方法,其中applicationDocumentsDirectory是一個非常簡單的方法,用于獲取應用Docouments目錄
AppDelegate.m

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
    // 當應用被中斷時候,將所有托管上下文中數據保存起來
    [self saveContext];
}

- (void)saveContext
{
    NSError *error = nil;
    // 獲取應用的托管對象上下文
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        // 如果托管對象上下文中包含了未保存的修改,執行保存,如果保存失敗記錄錯誤信息
        if ([managedObjectContext hasChanges] &&
            ![managedObjectContext save:&error])
        {
            NSLog(@"保存出現錯誤:%@, %@", error, [error userInfo]);
            abort();
        }
    }
}
// 初始化應用的托管對象上下文。
- (NSManagedObjectContext *)managedObjectContext
{
    // 如果_managedObjectContext已經被初始化過,直接返回該對象   
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }
    // 獲取持久化存儲協調器
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    // 如果持久化存儲協調器不為nil
    if (coordinator != nil)
    {
        // 創建NSManagedObjectContext對象
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        // 為NSManagedObjectContext對象設置持久化存儲協調器
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
    // 如果_managedObjectModel已經被初始化過,直接返回該對象
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    // 獲取實體模型文件對應的NSURL
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FKModel"
        withExtension:@"momd"];
    // 加載應用的實體模型文件,并初始化NSManagedObjectModel對象
    _managedObjectModel = [[NSManagedObjectModel alloc]
        initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    // 如果_persistentStoreCoordinator已經被初始化過,直接返回該對象
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    // 獲取SQLite數據庫文件的存儲目錄
    NSURL *storeURL = [[self applicationDocumentsDirectory]
        URLByAppendingPathComponent:@"Books.sqlite"];
    NSError *error = nil;
    // 以持久化對象模型為基礎,創建NSPersistentStoreCoordinator對象
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
        initWithManagedObjectModel:[self managedObjectModel]];
    // 設置持久化存儲協調器底層采用SQLite存儲機制,如果設置失敗記錄錯誤信息
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
        configuration:nil URL:storeURL options:nil error:&error])
    {
        NSLog(@"設置持久化存儲失敗:%@, %@", error, [error userInfo]);
        abort();
    }
    return _persistentStoreCoordinator;
}
// 獲取應用的Documents目錄
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
        inDomains:NSUserDomainMask] lastObject];
}

到此Core Data所依賴的環境基本上已經搭建完畢,應用執行增、刪、查、改操作直接調用managedObjectContext方法即可操作。

3.設計實體模型

Xcode中找到我們創建的Core Data文件,打開實體模型開始編輯,具體如下圖:

coredata02.png

下面我們添加一個簡單的實體,點擊上圖走下角的Add Entity,系統將會在ENTITIES列表下添加一個實體,將該實體重命名為項目所需的名字,此處為Bison

PS長按Add Entity將會顯示Add EntityAdd Fetch RequestAdd Configuration列表,可供選擇添加實體、抓取請求、配置。

選中Bison實體,通過點擊上圖右下角的Add Attribute按鈕,系統將會為該Bison實體添加一個屬性,將該屬性重命名所需的名字,此處重命名name,并為該屬性選擇類型,在此選String類型,注意:此處命名首字母不能大寫哦。

PS長按Add Attribute將會顯示Add AttributeAdd RelationshipAdd Configuration、Add Fetch Property列表,可供選擇添加屬性、關聯關系、抓取屬性,也可以通過 +來添加與刪除。

重復上面的操作增加一個birthDay的屬性,改屬性為date類型。實體設計完后,如下圖:

coredata03.png

然后單擊Xcode主菜單的Editor-->Create NSManagedObject Subclass菜單項,如果系統包含倆個以上的實體,Xcode將會彈出一個對話框讓選擇腰圍哪些實體生成NSManagedObject的子類,然后彈出對話框讓選擇NSManagedObject的子類的存儲路徑。選完之后Create按鈕即可。
經過上面的操作,為實體模型添加一個簡單的Bison實體,該實體包含倆個屬性,單不包含任何關聯關系。

4.Core Data數據的增刪查改

獲取托管對象上下文NSManagedObjectContext之后,接下來即可通過該對象來執行增、刪、查、改操作。

  • 添加實體
    添加實體的步驟如下:
    調用NSEntityDescriptioninsertNewObjectForEntityForName:inManagedObjectContext:靜態方法添加新實體。該方法的第1個參數為實體名,第2個參數為NSManagedObjectContext對象。為新實體設置屬性。調用NSManagedObjectContext對象的save:方法執行保存。如下代碼片段:
// 控制Core Data在托管對象上下文中創建一個新實體
    Bison* bison = [NSEntityDescription
                      insertNewObjectForEntityForName:@"Bison"
                      inManagedObjectContext:self.appDelegate.managedObjectContext];
    // 為新實體設置屬性
    bison.name = @"linbin";
    bison.birth_Day = [NSDate date];
    // 定義一個NSError對象,用于接受錯誤信息
    NSError *error;
    // 設置完實體屬性之后,調用托管對象上下文的`save:`方法將實體寫入數據庫,如果保存成功
    if ([self.appDelegate.managedObjectContext save:&error])
    {
        [[[UIActionSheet alloc] initWithTitle:@"保存成功" delegate:nil
                            cancelButtonTitle:@"確定" destructiveButtonTitle:nil
                            otherButtonTitles: nil] showInView:self.view];
    }
    else
    {
        NSLog(@"保存FKEvent實體出錯: %@,%@" , error ,[error userInfo]);
    }
  • 刪除實體
    刪除實體的步驟如下:
    首先獲取要刪除的實體,然后調用NSManagedObjectContext對象的deleteObject:方法刪除實體。最后調用NSManagedObjectContext對象的save:方法執行保存。如下代碼:
// 獲取將要刪除的實體
    Bison* deleteEvent = .....;
    // 從托管對象上下文中刪除指定對象
    [self.appDelegate.managedObjectContext deleteObject:deleteEvent];
    NSError *error;
    // 保存刪除操作,如果出現錯誤,顯示錯誤信息
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"刪除FKEvent實體出錯:%@,%@",error,[error userInfo]);
    }
  • 修改實體
    修改實體的步驟如下:
    首先獲取要修改的實體,必須處于NSManagedObjectContext管理下的實體;然后修改實體的屬性;再調用NSManagedObjectContext對象的save:方法執行保存。如下代碼:
// 獲取將要修改的實體
    Bison* updateEvent = .....;
    //修改實體的屬性
    .....
    //定義一個NSError對象,用于接收錯誤信息
    NSError *error;
    // 保存修改操作,如果出現錯誤,顯示錯誤信息
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"刪除FKEvent實體出錯:%@,%@",error,[error userInfo]);
    }
  • 查詢實體
    查詢實體的步驟如下:
    首先創建NSFetchRequest對象。然后通過NSEntityDescription對象設置NSFetchRequest對象將要抓取的實體。如果需要對抓取結果進行篩選,則需要通過NSPredicate對象設置篩選條件。如果需要對結果進行排序,還需要為NSFetchRequest添加多個NSSortDescriptor對象。再調用NSManagedObjectContext對象的executeFetchRequest:error:方法執行查詢,該查詢方法將會返回所有符合條件的實體組成的NSArray集合。如下代碼:
// 創建抓取數據的請求對象
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    // 設置要抓取哪種類型的實體
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Bison"
        inManagedObjectContext:self.appDelegate.managedObjectContext];
    // 設置抓取實體
    [request setEntity:entity];
    NSError *error = nil;
    // 執行抓取數據的請求,返回符合條件的數據
    eventArray = [[self.appDelegate.managedObjectContext
        executeFetchRequest:request error:&error] mutableCopy];

基本的方法到此就結束了,具體的詳情可以下載Demo查看
下載地址

推薦一款學習iOS開發的app_____|______| | 傳送門

好文推薦:仿window阿里旺旺登陸界面,打印機吐紙動畫效果

原文地址:http://allluckly.cn

如對你有幫助,請不要吝惜你的star和喜歡哦!

技術交流群:534926022(免費) 511040024(0.8/人付費)

版權歸?Bison所有 如需轉載請保留原文超鏈接地址!否則后果自負!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容