(一)CoreData - 基本使用

(一)CoreData - 基本使用

@(HTML5秘籍)[Objective-c, iOS, 本地存儲(chǔ)]


@一張占位圖,心曠神怡的開始閱讀吧

題目雖然說的是快速入門,但是CoreData是一門很博大精深的技術(shù),還是不要妄想幾天之內(nèi)能融會(huì)貫通。接下來幾篇文章會(huì)由淺入深,逐步講解如何使用并掌握CoreData。

最近一直在找一些關(guān)于日程管理的軟件,有一些感覺還不錯(cuò)的,但是總覺得自己想要一些功能都沒有,所以干脆就下手自己寫一個(gè)自己的。由于沒有后臺(tái)服務(wù)器做接口,一些數(shù)據(jù)只能暫時(shí)做本地存儲(chǔ)。在技術(shù)選型的時(shí)候做了一些調(diào)查,因?yàn)橹白鲞^PHP,對(duì)SQL印象蠻好的。但是對(duì)于一個(gè)移動(dòng)端應(yīng)用來說,基本不需要大量的存儲(chǔ)數(shù)據(jù),因此在FMDB,Realm和CoreData之間,選擇了蘋果的親兒子CoreData。

[TOC]

封裝CoreData管理工具

1. 創(chuàng)建一個(gè)自帶CoreData代碼的工程

在Xcode創(chuàng)建工程的時(shí)候,就可以創(chuàng)建一個(gè)帶有CoreData的工程,在APPdelegate中會(huì)生成關(guān)于CoreData的代碼。


@創(chuàng)建帶有CoreData的工程

下圖是Xcode7自動(dòng)創(chuàng)建的CoreData代碼,Xcode 8 做了修改,我們先說一下舊版的怎么玩,然后再看看新版怎么弄。

@Xcode 7自動(dòng)創(chuàng)建的CoreData代碼1

@Xcode 7自動(dòng)創(chuàng)建的CoreData代碼2

雖然說已經(jīng)生成了這些代碼,但是還是不能直接用,我們需要將代碼重新封裝一下。

2. 簡(jiǎn)單封裝CoreData管理類

① 創(chuàng)建一個(gè)繼承于NSObject的類 LTCoreDataManager

② 寫一個(gè)單例作為初始化方法

+ (LTCoreDataManager *)shareLTCoreDataManager
{
    static LTCoreDataManager *manager = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[LTCoreDataManager alloc] init];
    });

    return manager;
}

③ 將自動(dòng)生成的代碼粘貼到 LTCoreDataManager.m 中

④ 在 LTCoreDataManager.h 中加入方法聲明

+ (LTCoreDataManager *)shareLTCoreDataManager;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

⑤ 注意:應(yīng)在 LTCoreDataManager.h 中引入 <CoreData/CoreData.h>

創(chuàng)建CoreData模型文件

1.構(gòu)建模型文件

在創(chuàng)建工程的時(shí)候,如果選擇了使用CoreData,Xcode會(huì)自動(dòng)生成一個(gè)模型文件,模型文件的后綴為.xcdatamodeld。如果沒有選擇自動(dòng)生成模型文件,我們可以手動(dòng)創(chuàng)建一個(gè)模型文件Command + N,選擇 Core Data -> Data Model -> Next。

@創(chuàng)建好的模板

左側(cè)有三個(gè)選項(xiàng),entitiesfetch requestsconfigurations。

2.創(chuàng)建實(shí)體

長(zhǎng)按左下方的 Add Entity 按鈕,會(huì)彈出菜Add Entity、Add Fetch Request、Add Configuration。選擇 Add Entity創(chuàng)建一個(gè)實(shí)體,命名為Plan。如下圖所示

@Plan Entity

右側(cè)對(duì)應(yīng)著Attributes(屬性)、Relationships(關(guān)聯(lián)關(guān)系)、Fetched Properties(獲取操作)。
首先,添加兩個(gè)屬性,planName:type 為 String,planId:type 為 Integer64。
需要注意的是,屬性的首字母要小寫。

關(guān)于Type類型的說明

  • Undefined: 默認(rèn)值,參與編譯會(huì)報(bào)錯(cuò)
  • Integer 16: 整數(shù),表示范圍 -32768 ~ 32767
  • Integer 32: 整數(shù),表示范圍 -2147483648 ~ 2147483647
  • Integer 64: 整數(shù),表示范圍 –9223372036854775808 ~ 9223372036854775807
  • Float: 小數(shù),通過MAXFLOAT宏定義來看,最大值用科學(xué)計(jì)數(shù)法表示是 0x1.fffffep+127f
  • Double: 小數(shù),小數(shù)位比Float更精確,表示范圍更大
  • String: 字符串,用NSString表示
  • Boolean: 布爾值,用NSNumber表示
  • Date: 時(shí)間,用NSDate表示
  • Binary Data: 二進(jìn)制,用NSData表示
  • Transformable: OC對(duì)象,用id表示。可以在創(chuàng)建托管對(duì)象類文件后,手動(dòng)改為對(duì)應(yīng)的OC類名。使用的前提是,這個(gè)OC對(duì)象必須遵守并實(shí)現(xiàn)NSCoding協(xié)議。

3.添加關(guān)聯(lián)關(guān)系

再創(chuàng)建一個(gè)實(shí)體Task并添加響應(yīng)的屬性。

@添加關(guān)聯(lián)關(guān)系

Task添加關(guān)聯(lián)關(guān)系,點(diǎn)擊Relationships下面的加號(hào),新建一個(gè)關(guān)聯(lián)關(guān)系,命名為plan,inverse需要設(shè)置好Relationships之后才能設(shè)置。

關(guān)聯(lián)關(guān)系設(shè)置

  • delete rule: 定義關(guān)聯(lián)屬性的刪除規(guī)則。在當(dāng)前對(duì)象和其他對(duì)象有關(guān)聯(lián)關(guān)系時(shí),當(dāng)前對(duì)象被刪除后與之關(guān)聯(lián)對(duì)象的反應(yīng)。這個(gè)參數(shù)有四個(gè)枚舉值,代碼對(duì)應(yīng)著模型文件的相同選項(xiàng)。
  1. NSNoActionDeleteRule 刪除后沒有任何操作,也不會(huì)將關(guān)聯(lián)對(duì)象的關(guān)聯(lián)屬性指向nil。刪除后使用關(guān)聯(lián)對(duì)象的關(guān)聯(lián)屬性,可能會(huì)導(dǎo)致其他問題。
  2. NSNullifyDeleteRule 刪除后會(huì)將關(guān)聯(lián)對(duì)象的關(guān)聯(lián)屬性指向nil,這是默認(rèn)值。
  3. NSCascadeDeleteRule 刪除當(dāng)前對(duì)象后,會(huì)將與之關(guān)聯(lián)的對(duì)象也一并刪除。
  4. NSDenyDeleteRule 在刪除當(dāng)前對(duì)象時(shí),如果當(dāng)前對(duì)象還指向其他關(guān)聯(lián)對(duì)象,則當(dāng)前對(duì)象不能被刪除。
  • Type: 主要有兩種類型,To One和To Many,表示當(dāng)前關(guān)系是一對(duì)多還是一對(duì)一。

4.創(chuàng)建托管對(duì)象類文件

創(chuàng)建文件
選中后綴名為.xcdatamodeld的模型文件,選擇XcodeEditor -> Create NSManagedObject Subclass -> 選擇模型文件 -> 選擇實(shí)體,生成實(shí)體對(duì)應(yīng)的托管對(duì)象類文件。

@生成的文件

更新文件
當(dāng)前模型對(duì)應(yīng)的實(shí)體發(fā)生改變后,需要重新生成模型文件。生成步驟和上面一樣,主要是替換Category文件,托管對(duì)象文件不會(huì)被替換。生成文件時(shí)不需要?jiǎng)h除,直接替換文件。

增刪改查操作

1.插入操作

// 創(chuàng)建托管對(duì)象,并指明創(chuàng)建的托管對(duì)象所屬實(shí)體名
Plan *planObj = [NSEntityDescription insertNewObjectForEntityForName:@"Plan" inManagedObjectContext:context];
planObj.planName = @"計(jì)劃名字";
planObj.planId = [NSNumber numberWithInteger:1];

// 通過上下文保存對(duì)象,并在保存前判斷是否有更改
NSError *error = nil;
if (context.hasChanges) {
    [context save:&error];
}

// 錯(cuò)誤處理
if (error) {
    NSLog(@"CoreData Insert Data Error : %@", error);
}

通過NSEntityDescriptioninsert類方法,生成并返回一個(gè)Employee托管對(duì)象,并將這個(gè)對(duì)象插入到指定的上下文中。
managedObjectContext將操作的數(shù)據(jù)存放在緩存層,只有調(diào)用managedObjectContextsave方法后,才會(huì)真正對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,否則這個(gè)對(duì)象只是存在內(nèi)存中,這樣做避免了頻繁的數(shù)據(jù)庫(kù)訪問。

2.刪除操作

// 建立獲取數(shù)據(jù)的請(qǐng)求對(duì)象,指明對(duì)Plan實(shí)體進(jìn)行刪除操作
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];

// 創(chuàng)建謂詞對(duì)象,過濾出符合要求的對(duì)象,也就是要?jiǎng)h除的對(duì)象
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"planName = %@", @"計(jì)劃名字"];
[request setPredicate:predicate];

// 執(zhí)行獲取操作,找到要?jiǎng)h除的對(duì)象
NSError *error = nil;
NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];

// 遍歷符合刪除要求的對(duì)象數(shù)組,執(zhí)行刪除操作
[planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    [context deleteObject:obj];
}];

// 保存上下文
if (context.hasChanges) {
    [context save:nil];
}

// 錯(cuò)誤處理
if (error) {
    NSLog(@"CoreData Delete Data Error : %@", error);
}

3.更新操作

// 建立獲取數(shù)據(jù)的請(qǐng)求對(duì)象,并指明操作的實(shí)體為Plan
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];

// 創(chuàng)建謂詞對(duì)象,設(shè)置過濾條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"planName = %@", @"計(jì)劃名字"];
request.predicate = predicate;

// 執(zhí)行獲取請(qǐng)求,獲取到符合要求的托管對(duì)象
NSError *error = nil;
NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];
[planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    obj.planId = @2;
}];

// 將上面的修改進(jìn)行存儲(chǔ)
if (context.hasChanges) {
    [context save:nil];
}

// 錯(cuò)誤處理
if (error) {
    NSLog(@"CoreData Update Data Error : %@", error);
}

4.查詢操作

// 建立獲取數(shù)據(jù)的請(qǐng)求對(duì)象,指明操作的實(shí)體為Plan
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];

// 執(zhí)行獲取操作,獲取所有Plan托管對(duì)象
NSError *error = nil;
NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];
[planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Plan Name : %@, Id : %@", obj.planName, obj.planId);
}];

// 錯(cuò)誤處理
if (error) {
    NSLog(@"CoreData Ergodic Data Error : %@", error);
}

小結(jié)一下

看完上面一大堆,其實(shí)應(yīng)該還是不太理解。不過跟著步驟一步步走下來,應(yīng)該是可以簡(jiǎn)單實(shí)用了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容