iOS常見的數(shù)據(jù)存儲(chǔ)方式

plist存儲(chǔ)

plist的文件名不能叫做“info”、“Info”之類的,這是因?yàn)榕c系統(tǒng)屬性文件重名,而plist作為屬性列表是一種XML格式的文件,拓展名為plist。如果對(duì)象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,就可以使用writeToFile:atomically:方法直接將對(duì)象寫到屬性列表文件中,而Plist不能存儲(chǔ)自定義對(duì)象,成功后會(huì)寫入到Documents文件中(app);在ixcode中plist文件創(chuàng)建步驟為:NewFile —— IOS —— Resource —— Property List。
  plist存儲(chǔ)代碼實(shí)例:

  1. 加載plist
//獲取Plist文件的全路徑
NSString *path = [[NSBundle mainBundle] pathForResource:@"shops" ofType:@"plist"];
//加載plist文件
_shops = [NSArray arrayWithContentsOfFile:path];
  1. 屬性列表——?dú)w檔NSDictionary. 將數(shù)據(jù)封裝成字典,將字典持久化到Documents/stu.plist文件中
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict writeToFile:path atomically:YES];
  1. 屬性列表——恢復(fù)NSDictionary; 讀取Documents/stu.plist的內(nèi)容,實(shí)例化NSDictionary.
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
UserDefaults(偏好設(shè)置存儲(chǔ))

很多iOS應(yīng)用都支持偏好設(shè)置,比如保存用戶名、密碼、字體大小是否自動(dòng)登錄,等設(shè)置,iOS提供了一套標(biāo)準(zhǔn)的解決方案來為應(yīng)用加入偏好設(shè)置功能.偏好設(shè)置好處主要在于:不需要關(guān)心文件名,可以快速進(jìn)行鍵值對(duì)存儲(chǔ),能夠直接存儲(chǔ)基本數(shù)據(jù)類型,從而成功后會(huì)寫入到library(preference)中。
  UserDefaults(偏好設(shè)置存儲(chǔ))代碼實(shí)例:

  1. 寫入需保存的設(shè)置
[[NSUserDefaults standardUserDefaults] setFloat:18.0f forKey:@"text_size"]; 
  1. 讀取上次保存的設(shè)置
float textSize = [[NSUserDefaults standardUserDefaults] floatForKey:@"text_size"];
  1. 注意:IOS7之前UserDefaults設(shè)置數(shù)據(jù)時(shí),不是立即寫入可能還沒有寫入磁盤應(yīng)用程序就終止了導(dǎo)致數(shù)據(jù)丟失,可以通過調(diào)用synchornize方法強(qiáng)制寫入;
IOS7之后已經(jīng)實(shí)現(xiàn)即時(shí)寫入,可以省略此步
[defaults synchronize];  //'si?kr?naiz
NSKeyedArchiver

父類是NSCoder,歸檔成功會(huì)保存在Documents下,以".archive"后綴保存。如果對(duì)象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,可以直接用NSKeyedArchiver進(jìn)行歸檔和恢復(fù),不是所有的對(duì)象都可以直接用這種方法進(jìn)行歸檔,只有遵守了NSCoding協(xié)議的對(duì)象才可以。而NSCoding協(xié)議有2個(gè)方法: encodeWithCoder:每次歸檔對(duì)象時(shí),都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何歸檔對(duì)象中的每個(gè)實(shí)例變量,可以使用encodeObject:forKey:  方法歸檔實(shí)例變量 initWithCoder:每次從文件中恢復(fù)(解碼)對(duì)象時(shí),都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何解碼文件中的數(shù)據(jù)為對(duì)象的實(shí)例變量,可以使用decodeObject:forKey方法解碼實(shí)例變量。

  1. 系統(tǒng)對(duì)象通過NSKeyedArchiver保存與讀取數(shù)據(jù)
    1) 歸檔一個(gè)NSArray對(duì)象到Documents/array.archive
NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];

2)恢復(fù)(解碼)NSArray對(duì)象

NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

3)需要遵守

 - (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeInt:self.age forKey:@"age"];
    [encoder encodeFloat:self.height forKey:@"height"];
}
- (id)initWithCoder:(NSCoder *)decoder {
   self.name = [decoder decodeObjectForKey:@"name"];
   self.age = [decoder decodeIntForKey:@"age"];
   self.height = [decoder decodeFloatForKey:@"height"];
   return self;
}
  1. 自定義對(duì)象通過NSKeyedArchiver保存與讀取數(shù)據(jù)
 1)歸檔(編碼)
Person *person = [[[Person alloc] init] autorelease];
person.name = @"MJ";
person.age = 27;
person.height = 1.83f;
[NSKeyedArchiver archiveRootObject:person toFile:path];
2)恢復(fù)(解碼)
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
3)注意
   如果父類也遵守了NSCoding協(xié)議,應(yīng)該在encodeWithCoder:方法中加上一句:
[super encodeWithCode:encode];

確保繼承的實(shí)例變量也能被編碼,即也能被歸檔,應(yīng)該在initWithCoder:方法中加上一句:

self = [super initWithCoder:decoder];

確保繼承的實(shí)例變量也能被解碼,即也能被恢復(fù).

利用歸檔實(shí)現(xiàn)深復(fù)制
//比如對(duì)一個(gè)Person對(duì)象進(jìn)行深復(fù)制,臨時(shí)存儲(chǔ)person1的數(shù)據(jù)

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];

//解析data,生成一個(gè)新的Person對(duì)象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];

//分別打印內(nèi)存地址
NSLog(@"person1:0x%x", person1); // person1:0x7177a60
NSLog(@"person2:0x%x", person2); // person2:0x7177cf0
歸檔

NSKeyedArchiver專門用來做自定義對(duì)象歸檔

// 什么時(shí)候調(diào)用:當(dāng)一個(gè)對(duì)象要?dú)w檔的時(shí)候就會(huì)調(diào)用這個(gè)方法歸檔
// 作用:告訴蘋果當(dāng)前對(duì)象中哪些屬性需要?dú)w檔
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInt:_age forKey:@"age"];
}

// 什么時(shí)候調(diào)用:當(dāng)一個(gè)對(duì)象要解檔的時(shí)候就會(huì)調(diào)用這個(gè)方法解檔
// 作用:告訴蘋果當(dāng)前對(duì)象中哪些屬性需要解檔
// initWithCoder什么時(shí)候調(diào)用:只要解析一個(gè)文件的時(shí)候就會(huì)調(diào)用
- (id)initWithCoder:(NSCoder *)aDecoder
{
    #warning  [super initWithCoder]
    if (self = [super init]) {
        // 解檔
        // 注意一定要記得給成員屬性賦值
      _name = [aDecoder decodeObjectForKey:@"name"];
      _age = [aDecoder decodeIntForKey:@"age"];
    }
    return self;
}
SQLite及FMDB

采用SQLite數(shù)據(jù)庫(kù)來存儲(chǔ)數(shù)據(jù)。SQLite作為一中小型數(shù)據(jù)庫(kù),應(yīng)用ios中,跟前幾種保存方式相比,相對(duì)比較復(fù)雜一些,常用框架 FMDB,FMDB使用起來更加面向?qū)ο螅∪チ撕芏嗦闊?、冗余的C語(yǔ)言代碼,提供了多線程安全的數(shù)據(jù)庫(kù)操作方法,有效地防止數(shù)據(jù)混亂。

  1. 打開數(shù)據(jù)庫(kù)
     通過指定SQLite數(shù)據(jù)庫(kù)文件路徑來創(chuàng)建FMDatabase對(duì)象。
 FMDatabase *db = [FMDatabase databaseWithPath:path];
 if (![db open]) {
     NSLog(@"數(shù)據(jù)庫(kù)打開失?。?);
 }

文件路徑有三種情況:
1)具體文件路徑:如果不存在會(huì)自動(dòng)創(chuàng)建空字符串。
2)@"":會(huì)在臨時(shí)目錄創(chuàng)建一個(gè)空的數(shù)據(jù)庫(kù),當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)文件也被刪除。
3)nil:會(huì)創(chuàng)建一個(gè)內(nèi)存中臨時(shí)數(shù)據(jù)庫(kù),當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)會(huì)被銷毀。

  1. 執(zhí)行更新

在FMDB中,除查詢以外的所有操作,都稱為“更新”,create、drop、insert、update、delete等,使用executeUpdate:方法執(zhí)行更新

- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments

// 示例
[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"]

3 .執(zhí)行查詢

 - (FMResultSet *)executeQuery:(NSString*)sql, ...
  - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
  - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments

  // 查詢數(shù)據(jù)
  FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];

  // 遍歷結(jié)果集
  while ([rs next]) {
      NSString *name = [rs stringForColumn:@"name"];
      int age = [rs intForColumn:@"age"];
      double score = [rs doubleForColumn:@"score"];
  }

4 . 關(guān)于FMDatabaseQueue
  FMDatabase這個(gè)類是線程不安全的,如果在多個(gè)線程中同時(shí)使用一個(gè)FMDatabase實(shí)例,會(huì)造成數(shù)據(jù)混亂等問題,為了保證線程安全,F(xiàn)MDB提供方便快捷的FMDatabaseQueue類.
4.1 FMDatabaseQueue的創(chuàng)建


  FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
簡(jiǎn)單使用
  [queue inDatabase:^(FMDatabase *db) {
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];

      FMResultSet *rs = [db executeQuery:@"select * from t_student"];
      while ([rs next]) {
          // …
      }
  }];

4.2 使用事務(wù)

  [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
      [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];

      FMResultSet *rs = [db executeQuery:@"select * from t_student"];
      while ([rs next]) {
          // …
      }
  }];

4.3 事務(wù)回滾

  rollback = YES;
最后編輯于
?著作權(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)容