NSUserDefaults间坐、SQLite、CoreData

我們知道儲(chǔ)存方式分為兩種:內(nèi)存閃存邑退。內(nèi)存的存儲(chǔ)是臨時(shí)的竹宋,運(yùn)行時(shí)是有效的且效率很高,而閃存則是一種持久化儲(chǔ)存地技,但產(chǎn)生I/O消耗蜈七,效率相對(duì)低。我們把內(nèi)存中的數(shù)據(jù)轉(zhuǎn)移到閃存中進(jìn)行持久化的操作叫做歸檔莫矗。

然而兩者結(jié)合起來(lái)就是我們常用的數(shù)據(jù)存儲(chǔ)方法飒硅。通常我們所用到的:CoreData、SQLite作谚、NSUserDefaults等都是數(shù)據(jù)存儲(chǔ)的方法三娩。


  • plist NSArray/NSDictionary
  • NSCoding 歸檔反歸檔
  • NSUserDefaults用于存儲(chǔ)配置信息
  • SQLite用于存儲(chǔ)查詢需求較多的數(shù)據(jù)
  • CoreData用于規(guī)劃應(yīng)用中的對(duì)象

NSUserDefaults

輕量級(jí)本地?cái)?shù)據(jù)存儲(chǔ)

NSUserDefaults單例以key-value的形式存儲(chǔ)了一系列偏好設(shè)置,key是名稱妹懒,value是相應(yīng)的數(shù)據(jù)雀监。存/取數(shù)據(jù)時(shí)可以使用方法objectForKey:和setObject:forKey:來(lái)把對(duì)象存儲(chǔ)到相應(yīng)的plist文件中,或者讀取彬伦,既然是plist文件滔悉,那么對(duì)象的類型則必須是plist文件可以存儲(chǔ)的類型:NSNumber(NSInteger、float单绑、double)回官,NSString,NSDate搂橙,NSArray歉提,NSDictionary,BOOL.而如果需要存儲(chǔ)plist文件不支持的類型区转,比如圖片苔巨,可以先將其歸檔為NSData類型,再存入plist文件.

  • 對(duì)相同的Key賦值約等于一次覆蓋废离,要保證每一個(gè)Key的唯一性
  • NSUserDefaults 存儲(chǔ)的對(duì)象全是不可變的

保存在NSUserDefaults中的信息在你的應(yīng)用關(guān)閉后再次打開之后依然存在侄泽。保存信息到NSUserDefaults的一個(gè)例子就是保存用戶是否已登錄的狀態(tài)。我們把用戶的登錄狀態(tài)保存到NSUserDefaults以便用戶關(guān)閉應(yīng)用再次打開應(yīng)用的時(shí)候蜻韭,應(yīng)用能夠從NSUserDefaults獲取數(shù)據(jù)悼尾,根據(jù)用戶是否登錄展示不同的界面柿扣。有些應(yīng)用也用這個(gè)功能來(lái)保存機(jī)密數(shù)據(jù),比如用戶的訪問令牌闺魏,以便下次應(yīng)用登錄的時(shí)候未状,它們能夠使用這個(gè)令牌來(lái)再次認(rèn)證用戶。但是保存到NSUserDefaults的數(shù)據(jù)并沒有加密析桥,因此可以很容易的從應(yīng)用的包中看到司草。NSUserDefaults被存在一個(gè)以應(yīng)用的bundle id為名稱的plist文件中。

存儲(chǔ):

    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

     NSString *string = @"hahaha";

    [user setObject:string forKey:@"myKey"];

    [user synchronize];//寫完別忘了同步

讀扰菡獭:

            NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

            NSString *value = [user objectForKey:@"myKey"];

關(guān)于單例和NsuserDefaults參考玉令天下博客
關(guān)于使用參考sealband


SQLite

然而我們面對(duì)大量數(shù)據(jù)寫入的時(shí)候 輕量級(jí)儲(chǔ)存明顯不適用埋虹。SQLite的優(yōu)點(diǎn)就是他占用資源非常低,處理速度快娩怎。
SQLite是如何存儲(chǔ)的吨岭?
數(shù)據(jù)庫(kù)的存儲(chǔ)就像平時(shí)我們用的excel表格,它也是以表為單位峦树。橫縱分別對(duì)應(yīng)屬性名和自己的ID。

  1. 新建一個(gè)數(shù)據(jù)庫(kù)
  2. 新建一張表(table)
  3. 添加多個(gè)字段(column旦事,列魁巩,屬性)
  4. 添加多行記錄(row,每行存放多個(gè)字段對(duì)應(yīng)的值 三姐浮、SQL語(yǔ)句種類

  • 數(shù)據(jù)定義語(yǔ)句(DDL:Data Definition Language) 包括create和drop等操作 在數(shù)據(jù)庫(kù)中創(chuàng)建新表或刪除表(create table或 drop table)
  • 數(shù)據(jù)操作語(yǔ)句(DML:Data Manipulation Language) 包括insert谷遂、update、delete等操作 上面的3種操作分別用于添加卖鲤、修改肾扰、刪除表中的數(shù)據(jù)
  • 數(shù)據(jù)查詢語(yǔ)句(DQL:Data Query Language) 可以用于查詢獲得表中的數(shù)據(jù) 關(guān)鍵字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的關(guān)鍵字有where锁孟,order by次绘,group by和having

libsqlite3.dylib與libsqlite3.0.dylib是不同的鳍置,libsqlite3.dylib是一個(gè)指向libsqlite3.0.dylib的索引沦寂,而且總是指向最新的sqlite3動(dòng)態(tài)庫(kù)羽历。(如果有新的libsqlite3.1.dylib出現(xiàn)則會(huì)指向3.1)

/**
 *  單例方法實(shí)現(xiàn)
 *
 */
+(instancetype)sharedDataBase {

    static RYBaseHandle *baseHandle = nil;

    if (baseHandle == nil) {
        baseHandle = [[RYBaseHandle alloc] init];
    }

    return baseHandle;
}
/**
 *  定義sqlite實(shí)例
 */
static sqlite3 *sqlite;
/**
 *  打開數(shù)據(jù)庫(kù)
 */
-(void)openSqlite {

    if (sqlite != nil) {
        return;
    }
    NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    // pathComponent 路徑拼接不需要/
    // stringByAppendingFormat 需要/
    NSString *sqlitePath = [dataPath stringByAppendingPathComponent:@"favorite.db"];
    // utf8
    int result = sqlite3_open(sqlitePath.UTF8String, &sqlite);
    if (result == SQLITE_OK) {
    } else {
    }
}
/**
 *  創(chuàng)建表格
 */
-(void)createTableView {

    NSString *tableSqlite = @"create table if not exists collect(keyid integer primary key autoincrement, title text, duration integer, RYdescription text, category text, playUrl text, coverForFeed text)";

    int result = sqlite3_exec(sqlite, tableSqlite.UTF8String, NULL, NULL, NULL);
    if (result == SQLITE_OK) {
    } else {
    }

}

以及增刪改查等語(yǔ)句:
更新SQL:

 NSString *changeSql = [NSString stringWithFormat:@"update collect set title = '%@', duration = '%ld',RYdescription = '%@',category = '%@', playUrl = '%@', coverForFeed = '%@' where number = '%ld'",model.title,model.duration,model.RYdescription,model.category,model.playUrl,model.coverForFeed,number];

    int result = sqlite3_exec(sqlite, changeSql.UTF8String, NULL, NULL, nil);
    if (result == SQLITE_OK) {
    } else {
    }

插入:

    NSString *insert = [NSString stringWithFormat:@"insert into collect(title,duration,RYdescription,category,playUrl,coverForFeed) values('%@','%ld','%@','%@','%@', '%@')",model.title,model.duration,model.RYdescription,model.category,model.playUrl,model.coverForFeed];

    int result = sqlite3_exec(sqlite, insert.UTF8String, NULL, NULL, nil);
    if (result == SQLITE_OK) {
    } else {
    }


查詢 [返回?cái)?shù)組]:

/**
     *  創(chuàng)建數(shù)據(jù)庫(kù)跟隨指針烦磁,用來(lái)循環(huán)遍歷表格中的每一行
     */
    NSString *selectSql = @"select * from collect";
    sqlite3_stmt *stmt = nil;

    /**
     *  數(shù)據(jù)庫(kù)內(nèi)查詢
     *
     *  @param sqlite               數(shù)據(jù)庫(kù)名稱
     *  @param selectSql.UTF8String 查詢
     *  @param -1                   字?jǐn)?shù)限制 [-1 表示不限制]
     *  @param stmt                 跟隨指針對(duì)象查詢
     *  @param nil                  廓块?桃焕?亏钩?
     *
     *  @return 查詢結(jié)果
     */

    int result = sqlite3_prepare_v2(sqlite, selectSql.UTF8String, -1, &stmt, nil);
    /**
     初始化返回?cái)?shù)組

     - returns: 可變數(shù)組
     */
    NSMutableArray *array = [[NSMutableArray array] init];
    if (result == SQLITE_OK) {
        NSLog(@"查詢成功");
        /**
         *  逐行查詢
         */
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            const unsigned char *title = sqlite3_column_text(stmt, 1);// column列/欄
            int duration = sqlite3_column_int(stmt, 2);
            const unsigned char *RYdescription = sqlite3_column_text(stmt, 3);
            const unsigned char *category = sqlite3_column_text(stmt, 4);
            const unsigned char *playUrl = sqlite3_column_text(stmt, 5);
            const unsigned char *coverForFeed = sqlite3_column_text(stmt, 6);

            RYModelMain *model = [[RYModelMain alloc] init];
            model.title = [NSString stringWithUTF8String:(const char *)title];
            model.duration = duration;
            model.RYdescription = [NSString stringWithUTF8String:(const char *)RYdescription];
            model.category = [NSString stringWithUTF8String:(const char *)category];
            model.playUrl = [NSString stringWithUTF8String:(const char *)playUrl];
            model.coverForFeed = [NSString stringWithUTF8String:(const char *)coverForFeed];
            /**
             *  將找到的數(shù)據(jù)放入數(shù)組中返回
             */
            [array addObject:model];

        }

    } else {
    }

查詢 [返回布爾值]

NSString *seleSql = @"select * from collect";
    sqlite3_stmt *stmt = nil;

    int result = sqlite3_prepare_v2(sqlite, seleSql.UTF8String, -1, &stmt, nil);
    RYModelMain *model = [[RYModelMain alloc] init];

    if (result == SQLITE_OK) {
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            const unsigned char *title = sqlite3_column_text(stmt, 1);
            model.title = [NSString stringWithUTF8String:(const char *)title];

        }

    } else {
    }

    if ([model.title isEqualToString:title]) {
        return YES;
    } else {
        return NO;
    }

刪除:

 /**
     *  創(chuàng)建刪除sql
     */

    NSString *deleSql = [NSString stringWithFormat:@"delete from collect where title = '%@'",model.title];
    int result = sqlite3_exec(sqlite, deleSql.UTF8String, NULL, NULL, nil);
    if (result == SQLITE_OK) {
    } else {

    }

關(guān)閉數(shù)據(jù)庫(kù):

    sqlite = nil;

    int result = sqlite3_close(sqlite);
    if (result == SQLITE_OK) {

    } else {

    }

以及刪除表格:

  NSString *dropSql = @"drop table collect";

    int result = sqlite3_exec(sqlite, dropSql.UTF8String, NULL, NULL, nil);
    if (result  == SQLITE_OK) {

    } else {

    }


CoreData

SQLite用起來(lái)太過于麻煩莲绰,有些固定的語(yǔ)句特別容易出錯(cuò),這也就是為什么蘋果鼓勵(lì)用CoreData姑丑。CoreData優(yōu)點(diǎn):能夠合理管理內(nèi)存蛤签,避免使用sql的麻煩,高效.


CoreData關(guān)系圖
CoreData關(guān)系圖

構(gòu)成:

  • Managed Object Model:是描述應(yīng)用程序的數(shù)據(jù)模型栅哀,這個(gè)模型包含實(shí)體(Entity)震肮,特性(Property)称龙,讀取請(qǐng)求(Fetch Request)。
  • Managed Object Context:參與對(duì)數(shù)據(jù)對(duì)象進(jìn)行各種操作的全過程钙蒙,并監(jiān)測(cè)數(shù)據(jù)對(duì)象的變化茵瀑,以提供對(duì) undo/redo 的支持及更新綁定到數(shù)據(jù)的 UI。
  • Persistent Store Coordinator 相當(dāng)于數(shù)據(jù)文件管理器躬厌,處理底層的對(duì)數(shù)據(jù)文件的讀取與寫入马昨。
  • Managed Object 數(shù)據(jù)對(duì)象,與 Managed Object Context 相關(guān)聯(lián)扛施。
  • 圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器鸿捧,一般都是通過 control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數(shù)據(jù)疙渣。

具體步驟:

  1. 應(yīng)用程序先創(chuàng)建或讀取模型文件(后綴為xcdatamodeld)生成 NSManagedObjectModel 對(duì)象匙奴。Document應(yīng)用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(后綴為 xcdatamodeld)讀取。
  2. 然后生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對(duì)象妄荔,前者對(duì)用戶透明地調(diào)用后者對(duì)數(shù)據(jù)文件進(jìn)行讀寫泼菌。
  3. NSPersistentStoreCoordinator 負(fù)責(zé)從數(shù)據(jù)文件(xml, sqlite,二進(jìn)制文件等)中讀取數(shù)據(jù)生成 Managed Object,或保存 Managed Object 寫入數(shù)據(jù)文件啦租。
  4. NSManagedObjectContext 參與對(duì)數(shù)據(jù)進(jìn)行各種操作的整個(gè)過程哗伯,它持有 Managed Object。我們通過它來(lái)監(jiān)測(cè) Managed Object篷角。監(jiān)測(cè)數(shù)據(jù)對(duì)象有兩個(gè)作用:支持 undo/redo 以及數(shù)據(jù)綁定焊刹。這個(gè)類是最常被用到的。
  5. Array Controller, Object Controller, Tree Controller 這些控制器一般與 NSManagedObjectContext 關(guān)聯(lián)恳蹲,因此我們可以通過它們?cè)?nib 中可視化地操作數(shù)據(jù)對(duì)象虐块。

CoreData相關(guān)1
CoreData相關(guān)2
未完...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嘉蕾,隨后出現(xiàn)的幾起案子贺奠,更是在濱河造成了極大的恐慌,老刑警劉巖错忱,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敞嗡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡航背,警方通過查閱死者的電腦和手機(jī)喉悴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)玖媚,“玉大人箕肃,你說我怎么就攤上這事〗衲В” “怎么了勺像?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵障贸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我吟宦,道長(zhǎng)篮洁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任殃姓,我火速辦了婚禮袁波,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜗侈。我一直安慰自己篷牌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布踏幻。 她就那樣靜靜地躺著枷颊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪该面。 梳的紋絲不亂的頭發(fā)上夭苗,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音隔缀,去河邊找鬼听诸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蚕泽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桥嗤,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼须妻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了泛领?” 一聲冷哼從身側(cè)響起荒吏,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渊鞋,沒想到半個(gè)月后绰更,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锡宋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年儡湾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片执俩。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡徐钠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出役首,到底是詐尸還是另有隱情尝丐,我是刑警寧澤显拜,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站爹袁,受9級(jí)特大地震影響远荠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜失息,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一譬淳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧根时,春花似錦瘦赫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至替裆,卻和暖如春校辩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辆童。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工宜咒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人把鉴。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓故黑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親庭砍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子场晶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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