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

96
追逐iOS
0.5 2019.04.20 21:29 字数 650

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

  • plist文件,是XML属性的列表形式

    • ios 的偏好设置,就是基于plist文件
  • NSKeyedArchiver归档(遵循NSCodeing协议)

  • SQLite(需要自己写sql语句)

  • Core Data 苹果对SQLite的一个封装

今天我们先来说说plist文件,需要知道一个概念

沙盒文件

每一个iOS应用都有自己的沙盒文件,与其他的文件系统隔离,应用须待在自己的沙盒文件里面,其他应用不能访问该应用的沙盒文件

--

  • 如何看到应用的文件目录呢

NSHomeDirectory()这个方法

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 = @[@(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<NSCoding>

@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<NSSecureCoding>

@property (nonatomic, strong) NSString *name;

@property (nonatomic, assign) int age;


@end
  • 数据存储归档iOS11
//需要注意是:第二个参数是yes的话必须遵循NSSecureCoding,如果是NO的话可以是NSCoding协议
 NSData *data = [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 = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:&error];
     //保存的路径
    NSUserDefaults *defaults  =  [NSUserDefaults standardUserDefaults];
     [defaults setObject:data forKey:@"data_key"];
      //同步数据
     defaults synchronize];
iOS基础
Gupao