iOS 数据持久化

Posted by LML on March 23, 2020

前言

本系列文章主要介绍内存缓存和磁盘缓存的相关用法和原理。磁盘缓存其实就是 数据持久化。本文对 iOS 中常用的数据持久化方案进行介绍,主要有以下几种方案:

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite 3
  • CoreData

沙盒

在介绍各种数据持久化方案之前,先介绍下沙盒的机制和结构:iOS程序默认情况下只能访问程序自己的目录,这个目录被称为“沙盒”。结构如下:

  • 应用程序包
  • Documents
  • Library
    • Caches
    • Preferences
  • tmp
  • 应用程序包
    • 这里面存放的是应用程序的源文件,包括资源文件和可执行文件。比如 各种bundle文件
    • NSString *path = [[NSBundle mainBundle] bundlePath];
  • Documents
    • 数据持久化最常用的目录,适合存储重要数据,并将通过iCloud自动备份。
    • NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
  • Library/Caches
    • 适合存储体积大,不需要备份的非重要数据。
    • NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
  • Library/Preferences
    • 通常保存应用的设置信息。
  • tmp:
    • 系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除。

数据持久化方案

plist文件

  • 适用于
    • 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];
      

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);  
  • 注意
    • Preference是专门用来保存应用程序的配置信息的,一般不要在Preference中保存其他数据。
    • 如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。
    • 偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。

NSKeyedArchiver

  • 适用于
    • 遵循NSCoding协议

    ```
    @interface Person : NSObject @property (strong, nonatomic) UIImage *avatar; @property (copy, nonatomic) NSString *name; @property (assign, nonatomic) NSInteger age; @end //解档

  • (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”]; ```

  • 使用

    //保存
    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];
    //读取
    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];
    }
    

SQLite3

FMDB

参考

https://www.jianshu.com/p/7616cbd72845