4- coreData基本使用(增刪改查,干貨)

一.文章概要

當(dāng)前使用工具是XCode7.

這篇文章主要是寫了對于基本數(shù)據(jù)類型的"增刪改查"的操作,至于特殊類型比如UIImage,NSArray,NDDictionary我們在之后的幾篇文章中講到.

二.前話

從平常的使用來說,FMDB和coreData是項(xiàng)目中最經(jīng)常使用的兩個(gè)數(shù)據(jù)庫持久化方式.
CoreData 首先它是一個(gè) ORM框架姜胖。 SQLite 與 FMDB 其實(shí)都脫離不了關(guān)系型(relational)數(shù)據(jù) 而我們平時(shí)使用的編程語言卻是面向?qū)ο蟮奶陈樱际菍ο笮偷摹?br> 在 iOS 中末融,coreData 和 FMDB 關(guān)于這兩者的區(qū)別,我認(rèn)為主要是如下幾個(gè)方面

coreData

優(yōu)點(diǎn)
(1)映射之后 直接操作對象就能進(jìn)行增刪改查 更貼近 程序員的生活稳衬。
(2)我們不需要再寫SQL語句豌汇,避免了 SQL語句的繁瑣衡楞,比如說 SQL語句經(jīng)常要寫一大堆的包含 values(name,sex) 還要有對應(yīng)個(gè)數(shù)的?與前邊的()中的屬性個(gè)數(shù)對應(yīng)
缺點(diǎn)
(1) coreData沒有 java 中的 ORM 框架快速.尤其是多表操作的時(shí)候,效率并不是很高. java中的框架(Hibernate:特點(diǎn):可以把 SQL語句和面型對象的查詢語句混合使用.舉個(gè)例子:它可以把復(fù)雜的多表操作語句用一行查詢語句來執(zhí)行完畢)。而 coreData操作多表的時(shí)候,需要?jiǎng)?chuàng)建多個(gè)對應(yīng)數(shù)量的Requset,description,謂詞,篩選器恩溅。
(2)就單純的批量插入數(shù)據(jù)的速度 相比較FMDB 稍微慢一點(diǎn)點(diǎn)

三.FMDB

如果你之前用過sqlSever數(shù)據(jù)庫的話,繼續(xù)往下看,當(dāng)然你也可以直接跳過這一小節(jié)

首先,想必軟件工程專業(yè)或者相關(guān)專業(yè)的同學(xué)在學(xué)校學(xué)的就是sqlSever,對應(yīng)的數(shù)據(jù)庫課程也是免不了的.那么sql語句是我們必須要學(xué)習(xí)的."簡單查詢""多表查詢"等等這些都是我們要學(xué)習(xí)的.恭喜你,你已經(jīng)有了一定學(xué)習(xí)FMDB的基礎(chǔ)了.

再進(jìn)一步說,你之前從事java或者安卓開發(fā)工作的時(shí)候,用到了sqlSever,那么再次恭喜你,你基本已經(jīng)可以FMDB的那些基本功能了.

由此,我們可見,FMDB的使用方式和之前在其他語言中使用sqlSever數(shù)據(jù)庫的時(shí)候,是非常相似的.之前我們在使用sqlSever提到的那些關(guān)鍵點(diǎn)在FMDB中,也有體現(xiàn),比如"打開數(shù)據(jù)庫,關(guān)閉數(shù)據(jù)庫""手敲sql語句,執(zhí)行sql語句"......所以,FMDB,對于之前上手還是很熟悉,很簡單的.

你到現(xiàn)在還沒有使用過FMDB. 那也不用太煩惱和害怕,數(shù)據(jù)庫的基本格式都是固定的.既然是固定的,拷貝一段改改就可以了.

擴(kuò)展

(1)問:"什么時(shí)候使用coredata 什么時(shí)候使用FMDatabases?"

答: a. CoreData 在公司使用的比較少隔箍,用戶的比較多的是FMDatabases。

b.數(shù)據(jù)存儲的結(jié)構(gòu)比較簡單的時(shí)候脚乡,使用CoreData

c.CoreData 開發(fā)效率會高點(diǎn)蜒滩,為什么?因?yàn)樗敲嫦驅(qū)ο蟮模也挥脤憇ql語句. FMDatabases 數(shù)據(jù)結(jié)果比較復(fù)雜的時(shí)候奶稠,表與表之間的關(guān)聯(lián)比較多的時(shí)候使用.

(2)coreData 其實(shí)底層也是要寫sql 語句的俯艰,coreData 幫我們把sql語句封裝。

四.你要的干貨,利用coreData來持久化數(shù)據(jù)

第一步,創(chuàng)建'模型文件'

描述
描述
描述
描述

第二步,創(chuàng)建'實(shí)體Entity'

創(chuàng)建實(shí)體對象

描述
描述

描述
描述

創(chuàng)建實(shí)體對象的屬性(屬性名,屬性類型和關(guān)聯(lián)實(shí)體)

描述
描述

問:什么是關(guān)聯(lián)實(shí)體???

答:其實(shí)就是我們創(chuàng)建另外的一個(gè)實(shí)體.這里添加關(guān)聯(lián)實(shí)體的意思就是,舉個(gè)例子我們?nèi)祟愑袀€(gè)寵物狗,那么反過來寵物狗也有個(gè)主人是人類. 這里說白了就是兩個(gè)對象之間的相互關(guān)聯(lián)

溫馨提示

描述
描述

第三步,創(chuàng)建'創(chuàng)建NSManagedObject的子類文件'

描述
描述
描述
描述
描述
描述
描述
描述

以下的代碼是系統(tǒng)默認(rèn)生成的,這里貼出是僅供對比查驗(yàn)使用,在文篇文章中沒有其它的意義.

創(chuàng)建出的子類代碼-Book+CoreDataProperties.h:

#import "Book.h"

NS_ASSUME_NONNULL_BEGIN

@interface Book (CoreDataProperties)

@property (nullable, nonatomic, retain) NSNumber *bookID;
@property (nullable, nonatomic, retain) NSString *bookName;
@property (nullable, nonatomic, retain) Student *student;

@end

NS_ASSUME_NONNULL_END

創(chuàng)建出的子類代碼-Book+CoreDataProperties.m:

#import "Book+CoreDataProperties.h"

@implementation Book (CoreDataProperties)

@dynamic bookID;
@dynamic bookName;
@dynamic student;

@end

創(chuàng)建出的子類代碼-Book.h:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Student;

NS_ASSUME_NONNULL_BEGIN

@interface Book : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

@end

NS_ASSUME_NONNULL_END

#import "Book+CoreDataProperties.h"

創(chuàng)建出的子類代碼-Book.m:

#import "Book.h"
#import "Student.h"

@implementation Book

// Insert code here to add functionality to your managed object subclass

@end

創(chuàng)建出的子類代碼-Student+CoreDataProperties.h:

#import "Student.h"

NS_ASSUME_NONNULL_BEGIN

@interface Student (CoreDataProperties)

@property (nullable, nonatomic, retain) NSNumber *id;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) Book *book;

@end

NS_ASSUME_NONNULL_END

創(chuàng)建出的子類代碼-Student+CoreDataProperties.m:

#import "Student+CoreDataProperties.h"

@implementation Student (CoreDataProperties)

@dynamic id;
@dynamic name;
@dynamic book;

@end

創(chuàng)建出的子類代碼-Student.h:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Book;

NS_ASSUME_NONNULL_BEGIN

@interface Student : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

@end

NS_ASSUME_NONNULL_END

#import "Student+CoreDataProperties.h"

創(chuàng)建出的子類代碼-Student.m:

#import "Student.h"
#import "Book.h"

@implementation Student

// Insert code here to add functionality to your managed object subclass

@end

第四步,創(chuàng)建'coreData的管理類'

我們暫時(shí)不做封裝,直接在UIViewController演示.

第五步,coreData操作-創(chuàng)建(獲取)上下文

這里的上下文在OC中,類似我們coreAnimation中用到的圖形上下文. OC中哪些有上下文?

在正式看下邊的'增刪改查'代碼之前,我們需要也別注意的是:

(0)在我們每次執(zhí)行四個(gè)操作的時(shí)候,都首先要保證上下文存在(還活著)

(1)并且代碼執(zhí)行在'異步主隊(duì)列中'

(2)'增'部分:創(chuàng)建保存對象部分,不是直接new或者alloc-init

(3)'查'部分:NSPredicate過濾條件(精確和非精確)

(4)'改'部分:'查'部分:NSPredicate過濾條件(精確和非精確)

(5)'刪'部分:'查'部分:NSPredicate過濾條件(精確和非精確)

第六步,coreData操作-創(chuàng)建上下文

上邊提到我們的演示文件類型是UIViewController,所以是在'viewDidLoad'方法中創(chuàng)建上下文,并且同時(shí)創(chuàng)建一個(gè)全局變量,保證上下文在我們執(zhí)行'增刪改查'的操作過程當(dāng)中不會被銷毀. 代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    //創(chuàng)建上下文
    [self createCoreDataContent];
}

創(chuàng)建上下文的方法:

- (IBAction)createCoreDataContent{
    //創(chuàng)建數(shù)據(jù)庫文件的路徑
    //    NSString *path = [NSHomeDirectory() stringByAppendingString:@"Doucments/ImortData"];
    //    NSFileManager *manager = [NSFileManager defaultManager];
    //    if (![manager fileExistsAtPath:path]) {
    //        [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    //    }
    //

    //documet目錄下
    NSString *doc  = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path = [doc stringByAppendingPathComponent:@"/student.db"];//注意不是:stringByAppendingString

    NSURL *url = [NSURL fileURLWithPath:path];
    NSLog(@"-----------------------------------");
    NSLog(@"data : %@",path);

    //創(chuàng)建文件,并且打開數(shù)據(jù)庫文件
    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    //給存儲器指定存儲的類型
    NSError *error;
    NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
    if (store == nil) {
        [NSException raise:@"添加數(shù)據(jù)庫錯(cuò)誤" format:@"%@",[error localizedDescription]];
    }

    //創(chuàng)建圖形上下文
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    context.persistentStoreCoordinator = psc;
    self.managedContext = context;
}

第七步,coreData操作-增(插入)

//插入數(shù)據(jù)
- (IBAction)insertData{
    NSLog(@"插入數(shù)據(jù)");
    //創(chuàng)建模型數(shù)據(jù)模型
    Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
    student.name = @"張三2";
    student.id = @(11);

    Book *book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:self.managedContext];
    book.bookID = @(121);
    book.bookName = @"<老人與海2>";

    student.book = book;

    Student *student2 = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
    student2.name = @"李四2";
    student2.id = @(23);

    Book *book2 = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:self.managedContext];
    book2.bookID = @(242);
    book2.bookName = @"<飛鳥集2>";

    student2.book = book2;

    //保存,用 save 方法
    NSError *error = nil;
    BOOL success = [self.managedContext save:&error];
    if (!success) {
        [NSException raise:@"訪問數(shù)據(jù)庫錯(cuò)誤" format:@"%@",[error localizedDescription]];
    }
}

第八步,coreData操作-查

//讀取數(shù)據(jù)庫文件
- (IBAction)readData{
    NSLog(@"讀取數(shù)據(jù)");
    dispatch_async(dispatch_get_main_queue(), ^{

        // 初始化一個(gè)查詢請求
        //  NSFetchRequest *request = [[NSFetchRequest alloc] init];
        // 設(shè)置要查詢的實(shí)體
        // request.entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.managedContext];

        //以上代碼簡寫成下邊
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

        // 設(shè)置排序(按照age降序)
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:NO];
        request.sortDescriptors = [NSArray arrayWithObject:sort];
        // 設(shè)置條件過濾(搜索name中包含字符串"zhang"的記錄锌订,注意:設(shè)置條件過濾時(shí)竹握,數(shù)據(jù)庫SQL語句中的%要用*來代替,所以%Itcast-1%應(yīng)該寫成*zhang*)
        // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*zhang*"];
        // request.predicate = predicate;

        // 執(zhí)行請求
        NSError *error = nil;
        NSArray *objs = [self.managedContext executeFetchRequest:request error:&error];
        if (error) {
            [NSException raise:@"查詢錯(cuò)誤" format:@"%@", [error localizedDescription]];
        }

        NSLog(@"-----------------------------------");
        // 遍歷數(shù)據(jù)
        int index = 0;
        for (NSManagedObject *obj in objs) {
            NSLog(@"%d---name=%@", index++,[obj valueForKey:@"name"]);
        }

        for (Student *stu in objs) {
            Book *book = stu.book;
            NSLog(@"%@---name=%@", stu.name,book.bookName);
        }

    });
}

第九步,coreData操作-改(更新)

//更新數(shù)據(jù)
- (IBAction)modifyData{
    // 如果是想做更新操作:只要在更改了實(shí)體對象的屬性后調(diào)用[context save:&error]辆飘,就能將更改的數(shù)據(jù)同步到數(shù)據(jù)庫
    //先從數(shù)據(jù)庫中取出所有的數(shù)據(jù),然后從其中選出要修改的那個(gè),進(jìn)行修改,然后保存


    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

    //設(shè)置過濾條件
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@",@"李四2"];
    request.predicate = pre;

    NSError *error = nil;
    NSArray *objs = [self.managedContext executeFetchRequest:request error:&error];
    if (error) {
         [NSException raise:@"查詢錯(cuò)誤" format:@"%@", [error localizedDescription]];
    }

    // 2.更新身高
    for (Student *stu in objs) {
        stu.name = @"被修改的新名字";
    }

   //保存,用 save 方法
   BOOL success = [self.managedContext save:&error];
   if (!success) {
       [NSException raise:@"訪問數(shù)據(jù)庫錯(cuò)誤" format:@"%@",[error localizedDescription]];
   }

}

第十步,coreData操作-刪

//刪除
- (IBAction)removeData:(id)sender{

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];

    //查到到你要?jiǎng)h除的數(shù)據(jù)庫中的對象
    NSPredicate *predic = [NSPredicate predicateWithFormat:@"name = %@",@"張三2"];
    request.predicate = predic;

    //請求數(shù)據(jù)
    NSArray *objs = [self.managedContext executeFetchRequest:request error:nil];

    for (Student *stu in objs) {
        [self.managedContext deleteObject:stu];
    }

    [self.managedContext save:nil];
}

小結(jié)

為了方便地測試上邊的代碼,我們可以把各個(gè)方法在界面上對應(yīng).比如下圖這樣:

描述
描述

到這里,對于coreData的基本操作"增刪改查"的基本操作剛和代碼就完成了.

具體的 Demo 代碼可以在我的 GitHub 上找到 Demo地址

交流


歡迎大家關(guān)注我的微博和我GitHub,我會不時(shí)分享和轉(zhuǎn)發(fā)一些大牛的技術(shù)貼和開源項(xiàng)目.
GitHub:https://github.com/lilongcnc
博客地址:http://www.lilongcnc.cc


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啦辐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蜈项,更是在濱河造成了極大的恐慌芹关,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件紧卒,死亡現(xiàn)場離奇詭異侥衬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門轴总,熙熙樓的掌柜王于貴愁眉苦臉地迎上來直颅,“玉大人,你說我怎么就攤上這事怀樟」Τィ” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵漂佩,是天一觀的道長棚菊。 經(jīng)常有香客問我催跪,道長,這世上最難降的妖魔是什么心剥? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任征堪,我火速辦了婚禮瘩缆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘佃蚜。我一直安慰自己庸娱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布谐算。 她就那樣靜靜地躺著熟尉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洲脂。 梳的紋絲不亂的頭發(fā)上斤儿,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音恐锦,去河邊找鬼往果。 笑死,一個(gè)胖子當(dāng)著我的面吹牛一铅,可吹牛的內(nèi)容都是我干的陕贮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼潘飘,長吁一口氣:“原來是場噩夢啊……” “哼肮之!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卜录,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤戈擒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后暴凑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峦甩,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凯傲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犬辰。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冰单,靈堂內(nèi)的尸體忽然破棺而出幌缝,到底是詐尸還是另有隱情,我是刑警寧澤诫欠,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布涵卵,位于F島的核電站,受9級特大地震影響荒叼,放射性物質(zhì)發(fā)生泄漏轿偎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一被廓、第九天 我趴在偏房一處隱蔽的房頂上張望坏晦。 院中可真熱鬧,春花似錦嫁乘、人聲如沸昆婿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仓蛆。三九已至,卻和暖如春挎春,著一層夾襖步出監(jiān)牢的瞬間看疙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工搂蜓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狼荞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓帮碰,卻偏偏與公主長得像相味,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子殉挽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

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