iOS应用存储数据的常用的方式之plist和归档

iOS应用创建的数据存储方式

  • plist文件,是XML属性的列表形式
    • ios 的偏好设置,就是基于plist文件
  • NSKeyedArchiver归档(遵循NSCodeing协议)
  • SQLite(需要自己写sql语句)
  • Core Data 苹果对SQLite的一个封装
今天我们先来说说plist文件,需要知道一个概念
沙盒文件
每一个iOS应用都有自己的沙盒文件,与其他的文件系统隔离,应用须待在自己的沙盒文件里面,其他应用不能访问该应用的沙盒文件
【iOS应用存储数据的常用的方式之plist和归档】--
  • 如何看到应用的文件目录呢
NSHomeDirectory()这个方法
iOS应用存储数据的常用的方式之plist和归档
文章图片
01-应用的文件目录.png
从上图中我们可以看到的目录, 主要目录的路径,开头Application,之前我们在UIApplication的时候有说过,UIApplication就代表一个程序的象征,所以iOS应用开头的路径一般都是Application
  • 关于目录文件的一些介绍
  • Documents目录
Documents保存应用运行时生成的需要持久化的数据,一般是iTunes同步设备时来使用备份的目录
  • tmp目录
tmp临时存储数据,就是当程序在次运行的时候,这些数据就会被系统删除
  • Library这个一般是开发人员使用的
Library里面存放了2个子目录CachesPreferences
Caches运行程序时生成的需要持久化数据的文件目录,一般下载的视频或者文件会存储在这个目录,存储的体积大
Preferences偏好设置文件目录,比如:账号 密码 等 会与iTunes同步设备时备份
  • 访问Documents目录
/* 第一个参数:要获取的目录 第二个参数:搜索的范围(NSUserDomainMask:在自己文件下搜索) 第三个参数:是否展开路径 */ NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;

  • 访问Caches
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;

1- 保存数据
//获取路径 NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject; //拼接文件路径 plist文件 NSString *filePath =[path stringByAppendingPathComponent:@"data.plist"]; //NSLog(@"%@",filePath); NSFileManager *manager = [NSFileManager defaultManager]; //判断文件或者文件夹是否存在 BOOL isYewOrNo = [manager fileExistsAtPath:filePath]; if (isYewOrNo) { NSArray *datas = [NSArray arrayWithContentsOfFile:filePath]; NSLog(@"%@",datas); }else{ //写入数据 NSArray *data = https://www.it610.com/article/@[@(110)]; [data writeToFile:filePath atomically:YES]; }

2- 保存偏好设置的数据 这个数据就会保存在Preferences目录
//获取文件 NSUserDefaults *defaluts = [NSUserDefaults standardUserDefaults]; // 设置数据 [defaluts setObject:@"CC" forKey:@"name_key"]; [defaluts setObject:@"18" forKey:@"age_key"]; //同步设置数据 [defaluts synchronize];

归档NSKeyedArchiver
  • 针对自定义的类进行数据存储
  • 要进行归档的类,必须遵循NSCoding协议
CCPerson类的.h文件 遵循NSCoding
@interface CCPerson : NSObject@property (nonatomic, strong) NSString *name; @property (nonatomic, assign) int age; @end

CCPerson类的.m文件 实现协议的方法
//解档 - (instancetype)initWithCoder:(NSCoder *)aDecoder{if (self = [super init]) { self.name =[aDecoder decodeObjectForKey:@"name_key"]; self.age = [[aDecoder decodeObjectForKey:@"age_key"] intValue]; }return self; }//归档 - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.name forKey:@"name_key"]; [aCoder encodeObject:@(self.age) forKey:@"age_key"]; }

自定义类的数据存储
//归档NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject; //拼接路径 NSString *filepath = [path stringByAppendingPathComponent:@"person.data"]; NSFileManager *manager = [NSFileManager defaultManager]; if ([manager fileExistsAtPath:filepath]) { CCPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filepath]; NSLog(@"%@--%d",person.name,person.age); }else { //创建对象 CCPerson *person = [[CCPerson alloc] init]; person.name = @"小名"; person.age = 18; BOOL isSuc = [NSKeyedArchiver archiveRootObject:person toFile:filepath]; NSLog(@"%@",(isSuc == YES ? @"成功":@"失败")); }

注意:苹果为了提高数据的安全性在iOS11推出了一个新的方法
+ (nullable NSData *)archivedDataWithRootObject:(id)object requiringSecureCoding:(BOOL)requiresSecureCoding error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0))

,来代替下面的归档的方法
  • 这2个方法在iOS11之后弃用, iOS10可以使用
+ (NSData *)archivedDataWithRootObject:(id)rootObject API_DEPRECATED("Use +archivedDataWithRootObject:requiringSecureCoding:error: instead", macosx(10.2,10.14), ios(2.0,12.0), watchos(2.0,5.0), tvos(9.0,12.0)); + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path API_DEPRECATED("Use +archivedDataWithRootObject:requiringSecureCoding:error: instead", macosx(10.2,10.14), ios(2.0,12.0), watchos(2.0,5.0), tvos(9.0,12.0));

如果使用iOS11或者以上的系统,那么自定义的类CCPerson要遵循NSSecureCoding协议
@interface CCPerson : NSObject@property (nonatomic, strong) NSString *name; @property (nonatomic, assign) int age; @end

  • 数据存储归档iOS11
//需要注意是:第二个参数是yes的话必须遵循NSSecureCoding,如果是NO的话可以是NSCoding协议 NSData *data = https://www.it610.com/article/[NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:&error]; NSLog(@"------%@",error.description); BOOL isSuc =[data writeToFile:filepath atomically:YES]; NSLog(@"%@",(isSuc == YES ? @"成功":@"失败"));

保存路径的更改,上面再使用归档保存自定义类的数据时,我们一般创建一个 来存储路径,方便我们使用,其实如果是账户类的数据保存,直接存储到NSUserDefaults可以
//创建对象 CCPerson *person = [[CCPerson alloc] init]; person.name = @"小名"; person.age = 18; NSError *error = nil; NSData *data = https://www.it610.com/article/[NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:&error]; //保存的路径 NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; [defaults setObject:data forKey:@"data_key"]; //同步数据 defaults synchronize];

    推荐阅读