詳解持久化Core Data框架的原理以及使用---轉(zhuǎn)自Bison的技術(shù)博客

1.原理部分

Core Data是一個純粹的面向?qū)ο罂蚣芄北停捎糜诠芾韺嶓w以及實體之間的關(guān)聯(lián)關(guān)系的持久化曹鸠,也就是我們通常所指的數(shù)據(jù)持久化。
Core Data底層的持久化存儲方式可以是SQLite數(shù)據(jù)庫斥铺,也可以是XML文檔彻桃,甚至可以直接以內(nèi)存作為持久化存儲設(shè)備。
Core Data的核心概念是實體仅父。實體是由Core Data管理的模型對象叛薯,它必須是NSManagedObject類或其子類的實例。實體與實體之間存在1-1笙纤、1-N耗溜、N-N、的關(guān)聯(lián)關(guān)系省容,整個應(yīng)用的所有實體以及實體之間的關(guān)聯(lián)關(guān)系被稱為托管對象模型NSManagedObiectModel抖拴。
Core Data的核心對象是托管對象上下文NSManagedObjectContext,所有實體都處于托管對象上下文管理中腥椒,Core Data應(yīng)用對實體所做的任何增阿宅、刪、查笼蛛、改操作都必須通過托管對象上下文來完成洒放。
開發(fā)者開發(fā)的應(yīng)用程序需要通過NSMannagedObjectContext對實體進行增、刪滨砍、查往湿、改操作,而NSMannagedObjectContext底層與持久化存儲協(xié)調(diào)銜接惋戏,持久化存儲協(xié)調(diào)器則負責(zé)管理底層的存儲形式比如:SQLite领追。
Core Data應(yīng)用中的核心API有如下幾個。

托管對象模型NSManagedObiectModel:該對象負責(zé)管理整個應(yīng)用的所有實體以及實體之間的關(guān)聯(lián)關(guān)系响逢。當(dāng)開發(fā)者使用Xcode的圖形界面設(shè)計了實體與實體的關(guān)聯(lián)關(guān)系之后绒窑,需要使用該對象來加載、管理應(yīng)用的托管對象模型舔亭。


持久化存儲協(xié)調(diào)器NSPeristentStoreCoordinator:負責(zé)管理底層的存儲文件些膨,例如SQLite數(shù)據(jù)庫等。


托管對象上下文NSManagedObjectContext:該對象是Core Data的核心對象钦铺,應(yīng)用對實體所做的任何增订雾、刪、查职抡、改操作都必須通過該對象來完成。


實體描述NSEntityDescription:該對象代表了關(guān)于某個實體的描述信息误甚,從某種程度來說缚甩,該對象相當(dāng)于實體的抽象谱净。實體描述定義了該實體的名字、實體的實現(xiàn)類擅威,并用一個集合定義了該實體包含的所有屬性壕探。


抓取請求NSFetchRequest:該對象封裝了查詢實體的請求,包括程序需要查詢哪些實體郊丛、查詢條件李请、排序規(guī)則等。抓取請求定義了本次查詢的實體的名字厉熟、抓取請求的查詢條件导盅,通過NSPredicate來表示,并用一個NSArray集合定義了所有的排序規(guī)則揍瑟。


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

  • 創(chuàng)建NSManagedObiectModel對象來加載管理應(yīng)用的托管對象模型绢片。
  • NSManagedObiectModel對象為基礎(chǔ)滤馍,根據(jù)實際需要創(chuàng)建NSPeristentStoreCoordinator對象,該對象確定Core Data底層數(shù)據(jù)的存儲形式底循。
  • NSManagedObiectModel對象為基礎(chǔ)巢株,創(chuàng)建NSMannagedObjectContext,該對象是Core Data進行持久化訪問的核心對象熙涤。
  • 對于普通的增阁苞、刪、查灭袁、改操作猬错,需要分別先創(chuàng)建實體、刪除實體茸歧、修改實體倦炒,然后調(diào)用NSMannagedObjectContext對象的save:方法將這些修改保存到底層存儲設(shè)備。
  • 如果要執(zhí)行查詢软瞎,則需要先創(chuàng)建NSFetchRequest對象逢唤,再調(diào)用NSMannagedObjectContextexecuteFetchRequest:error:方法執(zhí)行查詢,該方法返回所有匹配條件的實體組成的NSArray涤浇。

2.手動配置環(huán)境

iOS允許在創(chuàng)建項目時勾選“Use Core Data”復(fù)選框鳖藕,通過該方式創(chuàng)建的項目已經(jīng)完成了所有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應(yīng)用必須的核心API對象:NSManagedObiectModel栋盹、NSPeristentStoreCoordinatorNSManagedObjectContext修改應(yīng)用程序委托類的接口部分敷矫,在接口部分定義上面3個核心API的屬性例获,并增加一個對NSManagedObjectContext對象執(zhí)行存儲的方法、一個獲取應(yīng)用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中實現(xiàn)部分進行修改,初始化對象整葡,并實現(xiàn)saveContext方法件余,其中applicationDocumentsDirectory是一個非常簡單的方法,用于獲取應(yīng)用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
{
    // 當(dāng)應(yīng)用被中斷時候遭居,將所有托管上下文中數(shù)據(jù)保存起來
    [self saveContext];
}

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

到此Core Data所依賴的環(huán)境基本上已經(jīng)搭建完畢,應(yīng)用執(zhí)行增话侧、刪栗精、查、改操作直接調(diào)用managedObjectContext方法即可操作瞻鹏。

3.設(shè)計實體模型

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

coredata02.png

下面我們添加一個簡單的實體新博,點擊上圖走下角的Add Entity薪夕,系統(tǒng)將會在ENTITIES列表下添加一個實體,將該實體重命名為項目所需的名字赫悄,此處為Bison

PS長按Add Entity將會顯示Add Entity原献、Add Fetch Request馏慨、Add Configuration列表,可供選擇添加實體姑隅、抓取請求熏纯、配置。

選中Bison實體粤策,通過點擊上圖右下角的Add Attribute按鈕,系統(tǒng)將會為該Bison實體添加一個屬性误窖,將該屬性重命名所需的名字叮盘,此處重命名name,并為該屬性選擇類型霹俺,在此選String類型,注意:此處命名首字母不能大寫哦柔吼。

PS長按Add Attribute將會顯示Add AttributeAdd Relationship丙唧、Add Configuration愈魏、Add Fetch Property列表,可供選擇添加屬性想际、關(guān)聯(lián)關(guān)系培漏、抓取屬性,也可以通過 + 胡本、來添加與刪除牌柄。

重復(fù)上面的操作增加一個birthDay的屬性,改屬性為date類型侧甫。實體設(shè)計完后珊佣,如下圖:

coredata03.png

然后單擊Xcode主菜單的Editor-->Create NSManagedObject Subclass菜單項,如果系統(tǒng)包含倆個以上的實體披粟,Xcode將會彈出一個對話框讓選擇腰圍哪些實體生成NSManagedObject的子類咒锻,然后彈出對話框讓選擇NSManagedObject的子類的存儲路徑。選完之后Create按鈕即可守屉。
經(jīng)過上面的操作惑艇,為實體模型添加一個簡單的Bison實體,該實體包含倆個屬性胸梆,單不包含任何關(guān)聯(lián)關(guān)系敦捧。

4.Core Data數(shù)據(jù)的增刪查改

獲取托管對象上下文NSManagedObjectContext之后,接下來即可通過該對象來執(zhí)行增碰镜、刪兢卵、查、改操作绪颖。

  • 添加實體
    添加實體的步驟如下:
    調(diào)用NSEntityDescriptioninsertNewObjectForEntityForName:inManagedObjectContext:靜態(tài)方法添加新實體秽荤。該方法的第1個參數(shù)為實體名甜奄,第2個參數(shù)為NSManagedObjectContext對象。為新實體設(shè)置屬性窃款。調(diào)用NSManagedObjectContext對象的save:方法執(zhí)行保存课兄。如下代碼片段:
// 控制Core Data在托管對象上下文中創(chuàng)建一個新實體
    Bison* bison = [NSEntityDescription
                      insertNewObjectForEntityForName:@"Bison"
                      inManagedObjectContext:self.appDelegate.managedObjectContext];
    // 為新實體設(shè)置屬性
    bison.name = @"linbin";
    bison.birth_Day = [NSDate date];
    // 定義一個NSError對象,用于接受錯誤信息
    NSError *error;
    // 設(shè)置完實體屬性之后晨继,調(diào)用托管對象上下文的`save:`方法將實體寫入數(shù)據(jù)庫烟阐,如果保存成功
    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]);
    }
  • 刪除實體
    刪除實體的步驟如下:
    首先獲取要刪除的實體,然后調(diào)用NSManagedObjectContext對象的deleteObject:方法刪除實體紊扬。最后調(diào)用NSManagedObjectContext對象的save:方法執(zhí)行保存蜒茄。如下代碼:
// 獲取將要刪除的實體
    Bison* deleteEvent = .....;
    // 從托管對象上下文中刪除指定對象
    [self.appDelegate.managedObjectContext deleteObject:deleteEvent];
    NSError *error;
    // 保存刪除操作,如果出現(xiàn)錯誤餐屎,顯示錯誤信息
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"刪除FKEvent實體出錯:%@,%@",error,[error userInfo]);
    }
  • 修改實體
    修改實體的步驟如下:
    首先獲取要修改的實體檀葛,必須處于NSManagedObjectContext管理下的實體;然后修改實體的屬性腹缩;再調(diào)用NSManagedObjectContext對象的save:方法執(zhí)行保存屿聋。如下代碼:
// 獲取將要修改的實體
    Bison* updateEvent = .....;
    //修改實體的屬性
    .....
    //定義一個NSError對象,用于接收錯誤信息
    NSError *error;
    // 保存修改操作藏鹊,如果出現(xiàn)錯誤润讥,顯示錯誤信息
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"刪除FKEvent實體出錯:%@,%@",error,[error userInfo]);
    }
  • 查詢實體
    查詢實體的步驟如下:
    首先創(chuàng)建NSFetchRequest對象。然后通過NSEntityDescription對象設(shè)置NSFetchRequest對象將要抓取的實體盘寡。如果需要對抓取結(jié)果進行篩選象对,則需要通過NSPredicate對象設(shè)置篩選條件。如果需要對結(jié)果進行排序宴抚,還需要為NSFetchRequest添加多個NSSortDescriptor對象勒魔。再調(diào)用NSManagedObjectContext對象的executeFetchRequest:error:方法執(zhí)行查詢,該查詢方法將會返回所有符合條件的實體組成的NSArray集合菇曲。如下代碼:
// 創(chuàng)建抓取數(shù)據(jù)的請求對象
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    // 設(shè)置要抓取哪種類型的實體
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Bison"
        inManagedObjectContext:self.appDelegate.managedObjectContext];
    // 設(shè)置抓取實體
    [request setEntity:entity];
    NSError *error = nil;
    // 執(zhí)行抓取數(shù)據(jù)的請求冠绢,返回符合條件的數(shù)據(jù)
    eventArray = [[self.appDelegate.managedObjectContext
        executeFetchRequest:request error:&error] mutableCopy];

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

推薦一款學(xué)習(xí)iOS開發(fā)的app_____|______| | 傳送門

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

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

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

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

版權(quán)歸?Bison所有 如需轉(zhuǎn)載請保留原文超鏈接地址!否則后果自負喊式!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孵户,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子岔留,更是在濱河造成了極大的恐慌夏哭,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件献联,死亡現(xiàn)場離奇詭異竖配,居然都是意外死亡何址,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門进胯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來用爪,“玉大人,你說我怎么就攤上這事胁镐≠搜” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵盯漂,是天一觀的道長烁巫。 經(jīng)常有香客問我,道長宠能,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任磁餐,我火速辦了婚禮违崇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诊霹。我一直安慰自己羞延,他們只是感情好脾还,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布鄙漏。 她就那樣靜靜地躺著怔蚌,像睡著了一般桦踊。 火紅的嫁衣襯著肌膚如雪籍胯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音鲸湃,去河邊找鬼暗挑。 笑死,一個胖子當(dāng)著我的面吹牛垃它,可吹牛的內(nèi)容都是我干的烹看。 我是一名探鬼主播惯殊,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼土思,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了崎岂?” 一聲冷哼從身側(cè)響起冲甘,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫁审,沒想到半個月后律适,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捂贿,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡厂僧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年颜屠,在試婚紗的時候發(fā)現(xiàn)自己被綠了辰妙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甫窟。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖粗井,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浇衬,我是刑警寧澤懒构,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站耘擂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秩霍。R本人自食惡果不足惜冤灾,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一辕近、第九天 我趴在偏房一處隱蔽的房頂上張望归粉。 院中可真熱鬧,春花似錦糠悼、人聲如沸倔喂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽席噩。三九已至,卻和暖如春贤壁,著一層夾襖步出監(jiān)牢的瞬間悼枢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工脾拆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留馒索,地道東北人莹妒。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像绰上,于是被迫代替她去往敵國和親旨怠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.如何提出Core Data框架渔期? 由于SQLite API來操作數(shù)據(jù)庫的操作方式與OC的編程思想不相同。 2....
    Z_Aaron閱讀 591評論 0 1
  • 一疯趟、設(shè)計實體模型(打開FKModel.xcdatamodeld) 1.對象模型的三種對象 (1)實體:最核心的對象...
    Z_Aaron閱讀 480評論 0 2
  • 適讀對象: 需要入門Core Data的朋友; 像我一樣信峻,尚未學(xué)過數(shù)據(jù)庫相關(guān)課程,不太懂怎么寫SQLite語句的朋...
    AntonyWong閱讀 5,209評論 8 21
  • MagicalRecord是受Ruby on Rails 中 Active Record fetching便捷性的...
    smile小芳閱讀 1,351評論 0 2
  • 大牛晚上七點二十的火車踢步,大牛初步計劃了一下癣亚,下午五點出發(fā)就行,因為今天一直下雨获印,考慮早點出發(fā)會好些述雾。 直到下午一點...
    douhaolee閱讀 258評論 0 0