NSUserDefaults、SQLite、CoreData

我們知道儲存方式分為兩種:內存閃存。內存的存儲是臨時的,運行時是有效的且效率很高,而閃存則是一種持久化儲存,但產生I/O消耗,效率相對低。我們把內存中的數據轉移到閃存中進行持久化的操作叫做歸檔。

然而兩者結合起來就是我們常用的數據存儲方法。通常我們所用到的:CoreData、SQLite、NSUserDefaults等都是數據存儲的方法。


  • plist NSArray/NSDictionary
  • NSCoding 歸檔反歸檔
  • NSUserDefaults用于存儲配置信息
  • SQLite用于存儲查詢需求較多的數據
  • CoreData用于規劃應用中的對象

NSUserDefaults

輕量級本地數據存儲

NSUserDefaults單例以key-value的形式存儲了一系列偏好設置,key是名稱,value是相應的數據。存/取數據時可以使用方法objectForKey:和setObject:forKey:來把對象存儲到相應的plist文件中,或者讀取,既然是plist文件,那么對象的類型則必須是plist文件可以存儲的類型:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.而如果需要存儲plist文件不支持的類型,比如圖片,可以先將其歸檔為NSData類型,再存入plist文件.

  • 對相同的Key賦值約等于一次覆蓋,要保證每一個Key的唯一性
  • NSUserDefaults 存儲的對象全是不可變的

保存在NSUserDefaults中的信息在你的應用關閉后再次打開之后依然存在。保存信息到NSUserDefaults的一個例子就是保存用戶是否已登錄的狀態。我們把用戶的登錄狀態保存到NSUserDefaults以便用戶關閉應用再次打開應用的時候,應用能夠從NSUserDefaults獲取數據,根據用戶是否登錄展示不同的界面。有些應用也用這個功能來保存機密數據,比如用戶的訪問令牌,以便下次應用登錄的時候,它們能夠使用這個令牌來再次認證用戶。但是保存到NSUserDefaults的數據并沒有加密,因此可以很容易的從應用的包中看到。NSUserDefaults被存在一個以應用的bundle id為名稱的plist文件中。

存儲:

    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

     NSString *string = @"hahaha";

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

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

讀取:

            NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

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

關于單例和NsuserDefaults參考玉令天下博客
關于使用參考sealband


SQLite

然而我們面對大量數據寫入的時候 輕量級儲存明顯不適用。SQLite的優點就是他占用資源非常低,處理速度快。
SQLite是如何存儲的?
數據庫的存儲就像平時我們用的excel表格,它也是以表為單位。橫縱分別對應屬性名和自己的ID。

  1. 新建一個數據庫
  2. 新建一張表(table)
  3. 添加多個字段(column,列,屬性)
  4. 添加多行記錄(row,每行存放多個字段對應的值 三、SQL語句種類

  • 數據定義語句(DDL:Data Definition Language) 包括create和drop等操作 在數據庫中創建新表或刪除表(create table或 drop table)
  • 數據操作語句(DML:Data Manipulation Language) 包括insert、update、delete等操作 上面的3種操作分別用于添加、修改、刪除表中的數據
  • 數據查詢語句(DQL:Data Query Language) 可以用于查詢獲得表中的數據 關鍵字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的關鍵字有where,order by,group by和having

libsqlite3.dylib與libsqlite3.0.dylib是不同的,libsqlite3.dylib是一個指向libsqlite3.0.dylib的索引,而且總是指向最新的sqlite3動態庫。(如果有新的libsqlite3.1.dylib出現則會指向3.1)

/**
 *  單例方法實現
 *
 */
+(instancetype)sharedDataBase {

    static RYBaseHandle *baseHandle = nil;

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

    return baseHandle;
}
/**
 *  定義sqlite實例
 */
static sqlite3 *sqlite;
/**
 *  打開數據庫
 */
-(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 {
    }
}
/**
 *  創建表格
 */
-(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 {
    }

}

以及增刪改查等語句:
更新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 {
    }


查詢 [返回數組]:

/**
     *  創建數據庫跟隨指針,用來循環遍歷表格中的每一行
     */
    NSString *selectSql = @"select * from collect";
    sqlite3_stmt *stmt = nil;

    /**
     *  數據庫內查詢
     *
     *  @param sqlite               數據庫名稱
     *  @param selectSql.UTF8String 查詢
     *  @param -1                   字數限制 [-1 表示不限制]
     *  @param stmt                 跟隨指針對象查詢
     *  @param nil                  ???
     *
     *  @return 查詢結果
     */

    int result = sqlite3_prepare_v2(sqlite, selectSql.UTF8String, -1, &stmt, nil);
    /**
     初始化返回數組

     - returns: 可變數組
     */
    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];
            /**
             *  將找到的數據放入數組中返回
             */
            [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;
    }

刪除:

 /**
     *  創建刪除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 {

    }

關閉數據庫:

    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用起來太過于麻煩,有些固定的語句特別容易出錯,這也就是為什么蘋果鼓勵用CoreData。CoreData優點:能夠合理管理內存,避免使用sql的麻煩,高效.


CoreData關系圖
CoreData關系圖

構成:

  • Managed Object Model:是描述應用程序的數據模型,這個模型包含實體(Entity),特性(Property),讀取請求(Fetch Request)。
  • Managed Object Context:參與對數據對象進行各種操作的全過程,并監測數據對象的變化,以提供對 undo/redo 的支持及更新綁定到數據的 UI。
  • Persistent Store Coordinator 相當于數據文件管理器,處理底層的對數據文件的讀取與寫入。
  • Managed Object 數據對象,與 Managed Object Context 相關聯。
  • 圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器,一般都是通過 control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數據。

具體步驟:

  1. 應用程序先創建或讀取模型文件(后綴為xcdatamodeld)生成 NSManagedObjectModel 對象。Document應用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(后綴為 xcdatamodeld)讀取。
  2. 然后生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對象,前者對用戶透明地調用后者對數據文件進行讀寫。
  3. NSPersistentStoreCoordinator 負責從數據文件(xml, sqlite,二進制文件等)中讀取數據生成 Managed Object,或保存 Managed Object 寫入數據文件。
  4. NSManagedObjectContext 參與對數據進行各種操作的整個過程,它持有 Managed Object。我們通過它來監測 Managed Object。監測數據對象有兩個作用:支持 undo/redo 以及數據綁定。這個類是最常被用到的。
  5. Array Controller, Object Controller, Tree Controller 這些控制器一般與 NSManagedObjectContext 關聯,因此我們可以通過它們在 nib 中可視化地操作數據對象。

CoreData相關1
CoreData相關2
未完...

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

推薦閱讀更多精彩內容