数据存储的三种方式

 
读取info.plist文件:
 NSDictionary *infoDict =  [NSBundle mainBundle].infoDictionary;
 NSString *version = infoDict[@"CFBundleVersion"];
一,属性列表
属性列表即plist文件,实质是xml文件。 

注意点:

    1. 根节点只能是NSArray或者NSDictionary 
    2. 如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中
  • 将一个NSDictionary对象归档到一个plist属性列表中
// 将数据封装成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母鸡" forKey:@"name"];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 将字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
 
 
二,偏好设置
     用于保存APP的设置,例如是否记住密码、是否接受推送、保存字体大小等。
// 保存数据
-(void)saveData
{
    // 1.获取偏好设置
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    // 2.保存数据
    [userDefaults setObject:@"传智播客" forKey:@"itcastKey"];
    [userDefaults setBool:YES forKey:@"isGoodKey"];
 
/*注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入
*/ 
  // 3.同步数据(iOS8)
    [userDefaults synchronize];
}

// 读取数据
-(void)readData
{
    // 1.获取偏好设置
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    // 2.读取数据
    NSLog(@"%@",[userDefaults objectForKey:@"itcastKey"]);
}
 
 
三,归档可以将任意类型的对象,编码后以二进制的形式保存。
在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦;
偏好设置(将所有的东西都保存在同一个文件夹下面,且主要用于存储应用的设置信息)
归档优势:因为前两者都有一个致命的缺陷,只能存储常用的类型。归档可以实现把自定义的对象存放在文件中。
 
注意点:
  1. 需要归档的自定义类,必须实现<NSCoding>协议,告诉系统需要归档和解档哪些属性。
  2. 若对象的属性中有自定义类型,则该类也需要实现<NSCoding>协议。
// 保存数据
-(void)saveData
{
    // 1.创建对象
    CZPerson *person = [CZPerson new];
    person.name = @"Jack";
    person.age = 18;

    // 2.实现<NSCoding>协议

    // 3.获取文件路径
    NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [documents stringByAppendingPathComponent:@"person.data"];

    // 4.编码并保存(归档)
    [NSKeyedArchiver archiveRootObject:person toFile:filePath];
}

// 读取数据
-(void)readData
{
    // 1.获取文件路径
    NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [documents stringByAppendingPathComponent:@"person.data"];

    // 2.解档
    CZPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    NSLog(@"%@",person.name);
}
 
 实现<NSCoding>协议
  • encodeWithCoder什么时候调用:对象归档时候调用
 
  • encodeWithCoder作用:告诉系统对象里的哪些属性需要归档,怎么去归档,根据一个key去归档,目的就是以后取的时候,也根据这个key去取数据。
// 编码
-(void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}
  • initWithCoder作用:告诉系统对象里的哪些属性需要解档,怎么去解档,根据之前存储的key去解档
    • initWithCoder是一个初始化方法,需要先初始化父类的,但是不能调用[super initWithCoder:],因为父类NSObject没有遵守NSCoding协议。
    3> initWithCoder什么时候需要调用[super initWithCoder:]
    • initWithCoder原理:只要解析文件就会调用,xib,storyboard都是文件,因此只要解析这两个文件,就会调用initWithCoder。
    • 因此如果在storyboard使用自定义view,重写initWithCoder方法,一定要调用[super initWithCoder:],因为只有系统才知道怎么解析storyboard,如果没有调用,就解析不了这个文件。
// 解码,实例化
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init])
    {//将对象的一些属性保存,没有设置的属性不作保存
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}
 

两个方法的区别与使用场景
/// 解归档 : 这个方法是把视图从bundle加载到内存.视图的frame可能不准
//- (instancetype)initWithCoder:(NSCoder *)aDecoder
//{
//    if (self = [super initWithCoder:aDecoder]) {
//        NSLog(@"%s",__func__);
//    }
//    return self;
//}

/// 视图被唤醒的方法.在这个方法里面可以拿到准确frame的视图
- (void)awakeFromNib
{
 
}
 
//读取JSON文件,转模型
+ (NSArray *)projects {
    // 1. 文件路径
    NSString *path = [[NSBundle mainBundle] pathForResource:@"more_project.json" ofType:nil];
    // 2. 读取文件内容 -  二进制数据
    NSData *data = [NSData dataWithContentsOfFile:path];
    // 3. 解析JSON 专门用来解析JSON的类 NSJSONSerialization
    /**
     看到options先传0.没有达到效果再来看枚举值
     */
    NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    // 声明一个可变的数组
    NSMutableArray *projects = [NSMutableArray array];
    // 4. 遍历数据,把字典转成模型 - 使用block来遍历数组
    [json enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        CZProject *project = [CZProject projectWithDict:obj];
        [projects addObject:project];
    }];
// 将可变数组,变成不可变 : 将线程不安全的类,变成了线程安全的类.同时,不可变的数组,外界不能修改的.
    return projects.copy;
}
 
原文地址:https://www.cnblogs.com/somethingWithiOS/p/5595053.html