iOS中經常使用的持久化存儲方式

前言

iOS中經常使用的持久化存儲方式有好幾種:數據庫

  • 偏好設置(NSUserDefaults)數組

  • plist文件存儲緩存

  • 歸檔安全

  • SQLite3網絡

  • Core Dataapp

這裏不細講數據庫,只針對性地講講文件存儲、歸檔/解檔、偏好設置等。dom

在此以前,咱們須要先講講沙盒(Sandbox)才能繼續講解。學習

沙盒

每一個iOS應用都有本身的應用沙盒(應用沙盒就是文件系統目錄),與其餘文件系統隔離。應用必須待在本身的沙盒裏,其餘應用不能訪問該沙盒。沙盒下的目錄以下:atom

  • Application:存放程序源文件,上架前通過數字簽名,上架後不可修改spa

  • Documents: 保存應⽤運行時生成的須要持久化的數據,iTunes同步設備時會備份該目錄。例如,遊戲應用可將遊戲存檔保存在該目錄

  • tmp: 保存應⽤運行時所需的臨時數據,使⽤完畢後再將相應的文件從該目錄刪除。應用 沒有運行時,系統也可能會清除該目錄下的文件。iTunes同步設備時不會備份該目錄。

  • Library/Caches: 保存應用運行時⽣成的須要持久化的數據,iTunes同步設備時不會備份 該目錄。⼀通常存儲體積大、不須要備份的非重要數據,好比網絡數據緩存存儲到Caches下

  • Library/Preference: 保存應用的全部偏好設置,如iOS的Settings(設置) 應⽤會在該目錄中查找應⽤的設置信息。iTunes同步設備時會備份該目錄

NSUserDefaults

NSUserDefaults是個單例類,用於存儲少許數據。NSUserDefaults實際上對plist文件操做的封裝,更方便咱們直接操做,通常用於存儲系統級別的偏好設置。好比咱們常常將登陸後的用戶的一些設置經過NSUserDefaults存儲到plist文件中。

有不少App,他們也是將用戶的帳號和密碼存儲在偏好設置中。咱們不講安全性問題,所以不討論存儲在偏好設置下是否安全。

使用起來很是簡單,以下:

1

2

3

4

5

6

7

8

9

10

11

12

 

// 寫入文件

- (void)saveUserName:(NSString *)userName password:(NSString *)password {

  [[NSUserDefaults standardUserDefaults] setObject:userName forKey:@"username"];

  [[NSUserDefaults standardUserDefaults] setObject:password forKey:@"password"];

  [[NSUserDefaults standardUserDefaults] synchronize];

}

 

// 在用的時候,就能夠讀取出來使用

NSString *userName = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"];

NSString *password = [[NSUserDefaults standardUserDefaults] objectForKey:@"password"];

 

存儲到偏好設置的只有系統已經提供好的類型,好比基本類型、NSNumber、NSDictionary、NSArray等。對於NSObject及繼承於NSObject的類型,是不支持的。以下:

1

2

3

4

5

6

7

 

NSObject *obj = [[NSObject alloc] init];

[[NSUserDefaults standardUserDefaults] setObject:obj forKey:@"obj"];

 

// 就會崩潰

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object <NSObject: 0x7fb502680cb0> for key obj'

 

plist存儲

有的時候,咱們須要將下載的數據存儲到文件中存儲起來,好比,有時候咱們將下載起來的城市的數據存儲到本地,當更新城市的順序時,下次也可以按照最後一次操做的順序來顯示出來。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

 

// 數據存儲,是保存到手機裏面,

// Plist存儲,就是把某些數據寫到plist文件中

// plist存儲通常用來存儲數組和字典

// Plist存儲是蘋果特有,只有蘋果才能生成plist

// plist不能存儲自定義對象,如NSObject、model等

NSDictionary *dict = @{@"age":@"18",@"name":@"USER"};

  

// 保存應用沙盒(app安裝到手機上的文件夾)

// Caches文件夾

// 在某個範圍內容搜索文件夾的路徑

// directory:獲取哪一個文件夾

// domainMask:在哪一個範圍下獲取 NSUserDomainMask:在用戶的範圍內搜索

// expandTilde是否展開全路徑,YES:展開

NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];

NSLog(@"%@",cachePath);

  

// 拼接文件路徑

NSString *filePath = [cachePath stringByAppendingPathComponent:@"data.plist"];

  

// 獲取應用沙盒

NSString *homePath = NSHomeDirectory();

NSLog(@"%@",homePath);

  

// File:文件全路徑 => 全部文件夾路徑 + 文件路徑

[dict writeToFile:filePath atomically:YES];

// 將數據取出來

NSLog(@"%@", [NSDictionary dictionaryWithContentsOfFile:filePath]);

 

咱們看看打印的結果:

1

2

3

4

5

6

7

8

 

2016-02-17 22:14:43.055 iOSPersistentStorageDemo[25471:809758] /Users/huangyibiao/Library/Developer/CoreSimulator/Devices/CF3A5A4C-486F-4A72-957B-2AD94BD90EC1/data/Containers/Data/Application/65E8F814-45E5-420C-A174-822A7830748E/Library/Caches

2016-02-17 22:14:43.055 iOSPersistentStorageDemo[25471:809758] /Users/huangyibiao/Library/Developer/CoreSimulator/Devices/CF3A5A4C-486F-4A72-957B-2AD94BD90EC1/data/Containers/Data/Application/65E8F814-45E5-420C-A174-822A7830748E

2016-02-17 22:14:43.056 iOSPersistentStorageDemo[25471:809758] {

    age = 18;

    name = USER;

}

 

注意:操做plist文件時,文件路徑必定要是全路徑。

歸檔(NSKeyedArchiver)

自定義對象應用範圍很廣,由於它對應着MVC中的Model層,即實體類。在程序中,咱們會在Model層定義不少的entity,例如User、Teacher、Person等。

那麼對自定義對象的歸檔顯得重要的多,由於不少狀況下咱們須要在Home鍵以後保存數據,在程序恢復時從新加載,那麼,歸檔即是一個好的選擇。

下面咱們自定義一個Person類:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

 

// 要使對象能夠歸檔,必須遵照NSCoding協議

@interface Person : NSObject<NSCoding>

 

@property (nonatomic, assign) int age;

@property (nonatomic, strong) NSString *name;

 

@end

 

@implementation Person

 

// 何時調用:只要一個自定義對象歸檔的時候就會調用

- (void)encodeWithCoder:(NSCoder *)aCoder {

    [aCoder encodeObject:self.name forKey:@"name"];

    [aCoder encodeInt:self.age forKey:@"age"];

}

 

- (id)initWithCoder:(NSCoder *)aDecoder {

    if (self = [super init]) {

       self.name = [aDecoder decodeObjectForKey:@"name"];

       self.age = [aDecoder decodeIntForKey:@"age"];

    }

    return self;

}

@end

 

如何將自定義對象歸檔和解檔:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

 

- (void)savePerson {

    // 歸檔:plist存儲不能存儲自定義對象,此時能夠使用歸檔來完成

    Person *person = [[Person alloc] init];

    person.age = 18;

    person.name = @"USER";

        

    // 獲取tmp目錄路徑

    NSString *tempPath = NSTemporaryDirectory();

        

    // 拼接文件名

    NSString *filePath = [tempPath stringByAppendingPathComponent:@"person.data"];

        

    // 歸檔

    [NSKeyedArchiver archiveRootObject:person toFile:filePath];

}

 

- (void)readPerson {

    // 獲取tmp  

    NSString *tempPath = NSTemporaryDirectory();

        

    // 拼接文件名

    NSString *filePath = [tempPath stringByAppendingPathComponent:@"person.data"];

        

    // 解檔

    Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    NSLog(@"%@ %d",p.name,p.age);

}

 

假設咱們定義了一個自定義的view,這個view是用xib或者storybard來生成的,那麼咱們我必定以下方法時,就須要以下實現:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

 

@implementation CustomView

 

// 解析xib,storyboard文件時會調用

- (id)initWithCoder:(NSCoder *)aDecoder {

    // 何時調用[super initWithCoder:aDecoder]?

    // 只要父類遵照了NSCoding協議,就調用[super initWithCoder:aDecoder]

    if (self = [super initWithCoder:aDecoder]) {

        NSLog(@"%s",__func__);

    }

    

    return  self;

}

 

@end

 

若是想要學習如何經過runtime來實現自動歸檔、解檔,請閱讀文章:經過runtime自動歸檔/解檔

相關文章
相關標籤/搜索