IOS 數據儲存五個方案

IOS儲存的五個方案

1. NSUserDefaults (偏好設置文件)
2. plist文件
3. 歸檔 (反歸檔)
4. SQLite3(FMDB)
5. CoreData

沙盒中相關路徑 介紹
- AppName.app 應用程序的程序包目錄,包含應用程序的本身。由于應用程序必須經過簽名,所以不能在運行時對這個目錄中的內容進行修改,否則會導致應用程序無法啟動。
- Documents/ 保存應用程序的重要數據文件和用戶數據文件等。用戶數據基本上都放在這個位置(例如從網上下載的圖片或音樂文件),該文件夾在應用程序更新時會自動備份,在連接iTunes時也可以自動同步備份其中的數據。
- Library:這個目錄下有兩個子目錄,可創建子文件夾??梢杂脕矸胖媚M粋浞莸幌M挥脩艨吹降臄祿?。該路徑下的文件夾,除Caches以外,都會被iTunes備份.
-   Library/Caches: 保存應用程序使用時產生的支持文件和緩存文件(保存應用程序再次啟動過程中需要的信息),還有日志文件最好也放在這個目錄。iTunes 同步時不會備份該目錄并且可能被其他工具清理掉其中的數據。
-   Library/Preferences: 保存應用程序的偏好設置文件。NSUserDefaults類創建的數據和plist文件都放在這里。會被iTunes備份。
- tmp/: 保存應用運行時所需要的臨時數據。不會被iTunes備份。iPhone重啟時,會被清空。

1. NSUserDefaults
NSUserDefaults 介紹

- 在運行時,您使用對象從用戶的默認數據庫中讀取應用程序使用的默認值。緩存信息,以避免每次需要默認值時都必須打開用戶的默認數據庫。設置默認值時,它將在您的流程中同步更改,并異步更改為持久性存儲和其他流程。
- NSUserDefaults 默認對象必須是一個屬性列表,也就是說,的一個實例(或對集合的實例的組合)NSData,NSString,NSNumber,NSDate,NSArray,或NSDictionary。如果要存儲任何其他類型的對象,通常應將其歸檔以創建NSData的實例。
- NSUserDefaults用來存儲 用戶設置 系統配置等一些小的數據。因為數據是明文存儲在 plist 文件中,不安全,即使只是修改一個 key 都會 load 整個文件,數據多加載慢( 內存),不適合存儲大量數據。
- 它是單例,也是線程安全的,是以鍵值對 key-value 的形式保存在沙盒中
- 沙盒路徑為 Library/Preferences。文件格式為 .plist
- NSUserDefaults返回的值是不可改變的,即使存儲的時候是可變的值。對相同的Key賦值約等于一次覆蓋。

//NSUserDefaults
//setObject中的key和value可以為除了nil外的任何對象
//setValue中的key只能為字符串 value可以為nil也可以為空對象[NSNull null]以及全部對象
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setObject:@"小明" forKey:@"name"];
//app意外退出或者中斷,數據不會被系統寫入所以命令synchronize直接同步到文件里,來避免數據的丟失。
[userDefault synchronize]; 

//取出對應的Key也就是name
[userDefault objectForKey:@"name"];

NSLog(@"name = %@",[userDefault objectForKey:@"name"]);
//打印  name = 小明
2. plist文件
plist文件 介紹

- plist的文件名不能單獨命名做"info"、"Info"之類的,是因為與系統屬文件重名
- 屬性列表是一種XML格式的文件,拓展名為plist
- 對象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,就可以使用writeToFile:atomically:方法直接將對象寫到屬性列表文件中
- Plist不能存儲自定義對象,成功后會寫入到Documents文件中(app)
- xcode中plist文件創建步驟:NewFile —— IOS —— Resource —— Property List

NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [cachePath stringByAppendingPathComponent:@"newInfo.plist"];

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"小紅" forKey:@"name"];
[dict setObject:@"18" forKey:@"age"];
[dict writeToFile:filePath atomically:YES];
    
NSDictionary *dics = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSLog(@"age:%@", [dics objectForKey:@"age"]);
newInfo.plist
3. 歸檔 (反歸檔)
歸檔 (反歸檔) 介紹
-之前將數據存儲到本地,只能是字符串、數組、字典、NSNuber、BOOL等容器類對象,不能將自定義對象進行保存,而通過歸檔能將所有的對象轉化為二進制數據存儲到文件中。
- 什么是歸檔
1.字典,數組,自定義的對象等在存儲時需要轉換為字節流NSData類型數據,再通過寫入文件來進行存儲。
- 什么是反歸檔
2.字節流轉換為字典,數組,自定義的類等
- 歸檔的缺點
3.歸檔保存數據,只能一次性歸檔保存以及一次性解壓。所以只能針對小量數據,而且對數據操作比較笨拙,即如果想改動數據的某一小部分,還是需要解壓整個數據或者歸檔整個數據。
- 歸檔的使用場景
4.有些應用沒聯網時,可以將手機有網時的數據存放在本地,沒網時,從本地中取出來這些數據展示。

//Students.h 文件
#import "Students.h"
//遵循NSCoding協議
@interface Students : NSObject<NSCoding>

@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) NSInteger age;

//Students.m 文件
#import "Students.m"
//需要重寫兩個協議方法
//-(void)encodeWithCoder:(NSCoder *)aCoder方法:
//-(id)initWithCoder:(NSCoder *)aDecoder方法:

// 當將一個自定義對象保存到文件的時候就會調用該方法
// 在該方法中說明如何存儲自定義對象的屬性
// 也就說在該方法中說清楚存儲自定義對象的哪些屬性
-(void)encodeWithCoder:(NSCoder *)aCoder
{
  NSLog(@"調用了encodeWithCoder:方法");
  [aCoder encodeObject:self.name forKey:@"name"];
  [aCoder encodeInteger:self.age forKey:@"age"];
 }

// 當從文件中讀取一個對象的時候就會調用該方法
// 在該方法中說明如何讀取保存在文件中的對象
// 也就是說在該方法中說清楚怎么讀取文件中的對象
-(id)initWithCoder:(NSCoder *)aDecoder
{
  NSLog(@"調用了initWithCoder:方法");
     //注意:在構造方法中需要先初始化父類的方法
     if (self=[super init]) {
      self.name=[aDecoder decodeObjectForKey:@"name"];
      self.age=[aDecoder decodeIntegerForKey:@"age"];
     }
     return self;
 }
//ViewController.h 文件
#import "ViewController.h"

Students *stu = [[Students alloc]init];
stu.name = @"掰掰";
stu.age = 8;
// 獲取文件路徑
NSString *docPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [docPath stringByAppendingPathComponent:@"Students.archiver"];
//進行歸檔
[NSKeyedArchiver archiveRootObject:stu toFile:path];
//反歸檔
Students *s1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path] ;
NSLog(@"---------%@", s1.name);//掰掰
NSLog(@"---------%ld", (long)s1.age);//8

采用多個對象儲存

- (IBAction)archiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver =  [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //將數據區連接到NSKeyedArchiver對象
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"ran1";
    p1.age = @"18";
    [archiver encodeObject:p1 forKey:@"person1"];
    
    Person *p2 = [[Person alloc] init];
    p2.name = @"ran2";
    p2.age = @"19";
    [archiver encodeObject:p2 forKey:@"person2"];

    [archiver finishEncoding];
    
    [data writeToFile:filePath atomically:YES];
}

- (IBAction)unarchiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    Person *p1 =  [unarchiver decodeObjectForKey:@"person1"];
    Person *p2 =  [unarchiver decodeObjectForKey:@"person2"];
    [unarchiver finishDecoding];
    
    NSLog(@"%@", p1.name);
    NSLog(@"%@", p2.name);
}
4. SQLite3
數據庫(splite):
splite是一個輕量級,跨平臺的小型數據庫,可移植性比較高,有著和MySpl幾乎相同的數據庫語句,以及無需服務器即可使用的優點:

數據庫的優點:

存儲大量的數據,存儲和檢索的速度非???
能對數據進行大量的聚合,這樣比起使用對象來講操作要快.
數據庫的缺點:

它沒有提供數據庫的創建方式
它的底層是基于C語言框架設計的, 沒有面向對象的API, 用起來非常麻煩
發雜的數據模型的數據建表,非常麻煩
在實際開發中我們都是使用的是FMDB第三方開源的數據庫,該數據庫是基于splite封裝的面向對象的框架.

    //sqlite3
    //1.獲取沙盒文件名
  NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
    NSLog(@"fileName = %@",fileName);
    
   int result = sqlite3_open(fileName.UTF8String, &_db); //創建(打開)數據庫,如果數據庫不存在,會自動創建  數據庫文件的路徑必須以C字符串(而非NSString)傳入
    
  if (result == SQLITE_OK) {
        NSLog(@"成功打開數據庫");
        
        char *errorMesg = NULL;
        const char *sql = "create table if not exists t_person (id integer primary key autoincrement, name text, age integer);";
        int result = sqlite3_exec(_db, sql, NULL, NULL, &errorMesg); //sqlite3_exec()可以執行任何SQL語句,比如創表、更新、插入和刪除操作。但是一般不用它執行查詢語句,因為它不會返回查詢到的數據
        
        if (result == SQLITE_OK) {
            NSLog(@"成功創建t_person表");
        } else {
            NSLog(@"創建t_person表失敗:%s",errorMesg);
        }
        
    } else {
        NSLog(@"打開數據庫失敗");
    }


//sqlite3 添加數據庫
- (IBAction)AddSqlite3:(UIButton *)sender {
 
    for (int i = 0; i < 10; i++) {
        
        NSString *name = [NSString stringWithFormat:@"小明-%d",arc4random()%100];
        int age = arc4random() % 100;
        
        char *errorMesg = NULL;
        NSString *sql = [NSString stringWithFormat:@"insert into t_person (name,age) values ('%@',%d);",name, age];
        int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
        
        if (result == SQLITE_OK) {
            NSLog(@"添加數據成功");
        } else {
            NSLog(@"添加數據失敗");
        }
    }

}

//刪除數據庫
- (IBAction)sqlite3delete:(id)sender 
{    
    char *errorMesg = NULL;
    NSString *sql = @"delete from t_person where age >= 0";
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"刪除成功");
    }else {
        NSLog(@"刪除失敗");
    }
    
}

//查詢數據庫
- (IBAction)query:(id)sender
 {    
    const char *sql = "select id, name, age from t_person;";  //"select id, name, age from t_person where age >= 50;"
    sqlite3_stmt *stmt = NULL;  //定義一個stmt存放結果集
    int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL); //檢測SQL語句的合法性
    
    if (result == SQLITE_OK) {
        NSLog(@"查詢語句合法");
        
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            
            int ID = sqlite3_column_int(stmt, 0);
            const unsigned char *sname = sqlite3_column_text(stmt, 1);
            NSString *name = [NSString stringWithUTF8String:(const char *)sname];
            int age = sqlite3_column_int(stmt, 2);
            
            NSLog(@"%d %@ %d",ID, name, age);
        }
    } else {
        NSLog(@"查詢語句非法");
    }
    
    
}
//修改數據庫
- (IBAction)sqliteUpdate:(id)sender {
    
    
    NSString *sql = @"update t_person set name = '哈哈' where age > 60";
    char *errorMesg = NULL;
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"更改成功");
    }else {
        NSLog(@"更改失敗");
    }
    
}

    
5. CoreData
CoreData核心類與結構

NSManagedObjectContext(數據上下文)

對象管理上下文,負責數據的實際操作(重要)
作用:插入數據,查詢數據,刪除數據,更新數據
NSPersistentStoreCoordinator(持久化存儲助理)

相當于數據庫的連接器
作用:設置數據存儲的名字,位置,存儲方式,和存儲時機
NSManagedObjectModel(數據模型)

數據庫所有表格或數據結構,包含各實體的定義信息
作用:添加實體的屬性,建立屬性之間的關系
操作方法:視圖編輯器,或代碼
NSManagedObject(被管理的數據記錄)

數據庫中的表格記錄
NSEntityDescription(實體結構)

相當于表格結構
NSFetchRequest(數據請求)

相當于查詢語句
后綴為.xcdatamodeld的包

里面是.xcdatamodel文件,用數據模型編輯器編輯
編譯后為.momd或.mom文件
 

參考博客鏈接

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