iOS 數據持久化

1、沙盒機制sql

沙盒就是一個文件,沙盒的目錄結構:數據庫

"應用程序包"
Documents
Library
    Caches
    Preferences
tmp

 文件夾解釋:安全

"應用程序包": 這裏面存放的是應用程序的源文件,包括資源文件和可執行文件。多線程

NSString *path = [[NSBundle mainBundle] bundlePath];  
NSLog(@"%@", path);

Documents: 最經常使用的目錄,iTunes同步該應用時會同步此文件夾中的內容,適合存儲重要數據。atom

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", path);

Library/Caches: iTunes不會同步此文件夾,適合存儲體積大,不須要備份的非重要數據。線程

NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", path);

Library/Preferences: iTunes同步該應用時會同步此文件夾中的內容,一般保存應用的設置信息。code

tmp: iTunes不會同步此文件夾,系統可能在應用沒運行時就刪除該目錄下的文件,因此此目錄適合保存應用中的一些臨時文件,用完就刪除。orm

NSString *path = NSTemporaryDirectory();
NSLog(@"%@", path);

2、plist文件(屬性列表)sqlite

plist文件是將某些特定的類,經過XML文件的方式保存在目錄中。對象

NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;

得到文件

 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
 NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];

存儲數據

NSArray *array = @[@"123", @"456", @"789"];
[array writeToFile:fileName atomically:YES];

讀取數據

NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);

說明:存儲時使用writeToFile: atomically:方法,讀取時使用arrayWithContentsOfFile:方法。

3、preference(偏好設置)

使用方法

//1.得到NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中寫入內容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1當即同步
[userDefaults synchronize];
//3.讀取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);

使用說明

  1. 偏好設置是專門用來保存應用程序的配置信息。

  2. 偏好設置會將全部數據保存到同一個文件中。即preference目錄下的一個以此應用包名來命名的plist文件。

4、NSKeyedArchiver(歸檔)

準備工做

  1. 遵循協議,設置屬性

//1.遵循NSCoding協議   
@interface Person : NSObject<NSCoding> 
  //2.設置屬性
  @property (strong, nonatomic) UIImage *avatar;
  @property (copy, nonatomic) NSString *name;
  @property (assign, nonatomic) NSInteger age;  
@end

  2.實現協議方法

//解檔  
- (id)initWithCoder:(NSCoder *)aDecoder {
      if ([super init]) {
          self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
          self.name = [aDecoder decodeObjectForKey:@"name"];
          self.age = [aDecoder decodeIntegerForKey:@"age"];
      }
      return self;
  }
  //歸檔
- (void)encodeWithCoder:(NSCoder *)aCoder {
      [aCoder encodeObject:self.avatar forKey:@"avatar"];
      [aCoder encodeObject:self.name forKey:@"name"];
      [aCoder encodeInteger:self.age forKey:@"age"];
  }

  3.具體使用

   1. 須要把對象歸檔是調用NSKeyedArchiver的工廠方法 archiveRootObject: toFile: 方法。

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];  Person *person = [[Person alloc] init];
  person.avatar = self.avatarView.image;
  person.name = self.nameField.text;
  person.age = [self.ageField.text integerValue];
  [NSKeyedArchiver archiveRootObject:person toFile:file];

  2.須要從文件中解檔對象就調用NSKeyedUnarchiver的一個工廠方法 unarchiveObjectWithFile: 便可。

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];  Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
  if (person) {
     self.avatarView.image = person.avatar;
     self.nameField.text = person.name;
     self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
  }

說明:

  1. 若是須要歸檔的類是某個自定義類的子類時,就須要在歸檔和解檔以前先實現父類的歸檔和解檔方法。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法;

  2. 歸檔在iOS中是另外一種形式的序列化,只要遵循了NSCoding協議的對象均可以經過它實現序列化。因爲決大多數支持存儲數據的Foundation和Cocoa Touch類都遵循了NSCoding協議,

5、SQLite(FMDB)

FMDB有三個主要的類:FMDatabase、FMResultSet、FMDatabaseQueue

FMDatabase:一個FMDatabase對象就表明一個單獨的SQLite數據庫,用來執行SQL語句

FMResultSet:使用FMDatabase執行查詢後的結果集

FMDatabaseQueue:用於在多線程中執行多個查詢或更新,它是線程安全的

使用方法

 打開數據庫  須要導入sqlite3.dylib

NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.db"];
FMDatabase *database = [FMDatabase databaseWithPath:path];    
if (![database open]) {
    NSLog(@"數據庫打開失敗!");
}

值得注意的是,Path的值能夠傳入如下三種狀況:

  • 具體文件路徑,若是不存在會自動建立

  • 空字符串@"",會在臨時目錄建立一個空的數據庫,當FMDatabase鏈接關閉時,數據庫文件也被刪除

  • nil,會建立一個內存中臨時數據庫,當FMDatabase鏈接關閉時,數據庫會被銷燬

更新數據庫

//經常使用方法有如下3種:   
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
//示例
[database executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"];   
//或者  
[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES(?, ?)", @"Bourne", [NSNumber numberWithInt:42]];

說明:在FMDB中,除查詢之外的全部操做,都稱爲「更新」, 如:create、drop、insert、update、delete等操做,使用executeUpdate:方法執行更新。

 查詢數據庫

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

應用實例

//1.執行查詢
FMResultSet *result = [database executeQuery:@"SELECT * FROM t_person"];
//2.遍歷結果集
while ([result next]) {
    NSString *name = [result stringForColumn:@"name"];
    int age = [result intForColumn:@"age"];
}

線程安全

建立隊列

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

使用隊列

[queue inDatabase:^(FMDatabase *database) {    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_1", [NSNumber numberWithInt:1]];    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_2", [NSNumber numberWithInt:2]];    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_3", [NSNumber numberWithInt:3]];      
          FMResultSet *result = [database executeQuery:@"select * from t_person"];    
         while([result next]) {   
         }    
}];

包裝事務到隊列中

[queue inTransaction:^(FMDatabase *database, BOOL *rollback) {    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_1", [NSNumber numberWithInt:1]];    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_2", [NSNumber numberWithInt:2]];    
          [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_3", [NSNumber numberWithInt:3]];      
          FMResultSet *result = [database executeQuery:@"select * from t_person"];    
             while([result next]) {   
             }   
           //回滾
           *rollback = YES;  
    }];

說明:在多個線程中同時使用一個FMDatabase實例是不明智的。不要讓多個線程分享同一個FMDatabase實例,它沒法在多個線程中同時使用。 若是在多個線程中同時使用一個FMDatabase實例,會形成數據混亂等問題。因此,使用FMDatabaseQueue,它是線程安全的

6、CoreData

地址:CoreData的使用

相關文章
相關標籤/搜索