本文主要对NSUserDefaults、plist(属性列表 property list)、archive(归档)这三种基础的数据持久化进行研究
在讨论这三种具体的方法之前,需要了解下iOS中的“沙盒”,也就是数据存储的地方,在iOS中,每个应用的沙盒都是独立的,在没有允许的情况下,不同的应用之间是不能进行信息的交互的。每个应用的“沙盒”这样一些目录:
1、Documents:这个目录用于存储非常大的文件或者是更新频率非常高同时需要备份的文件(游戏应用可以用来存放游戏存档),这个目录下的文件会在iTunes和iCloud中备份,访问方法为:
// 第二个属性NSUserDomainMask表示用户的文件夹,第三个属性选择是否使用绝对路径,使用NO,则Documents前面的路径用~表示
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO) lastObject];
2、Library:这个目录下面又分为Preferences和Caches两个目录:
(1)Preference:从名字就能理解,这是存放用户偏好设置的地方,例如QQ中选择是否自动登录和是否记住用户名和密码等这些操作,这个目录下的文件会在iTunes和iCloud中备份,访问方法:
通过NSUserDefault来读写里面的数据
(2)Caches:缓存文件夹,存储体积较大,更新频率高,很重要但是不需要备份的数据,这个目录下的文件不会在iTunes和iCloud中备份
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, No)lastObject];
3、tmp:临时文件,保存程序所需要的临时数据,不需要的时候就可以删除,同时,当APP不运行的时候,这个文件夹是有可能被清空的。这个目录下的文件是不会在iTunes和iCloud中备份的。访问方法:
NSString *tmpPath = NSTemporaryDirectory();
说明完iOS中的沙盒,下面就通过具体的代码来说明这4种数据持久化的使用
1、NSUserDefaults:
// 调用应用中的单例对象来存值
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"auto_login"];
[[NSUserDefaults standardUserDefaults]setObject:@"nineteen" forKey:@"userName"];
// 调用单例对象的set方法后,不是立即进行存储,原理上面是会设置一个固定的时间戳定时写入数据,那么就有可能发生还有到达时间戳去写入数据的时候由于一些原因应用程序就停止运行了,这样的话就无法写入数据。所以使用以下代码进行强制立即写入数据到磁盘
[[NSUserDefaults standardUserDefaults]synchronize];
// 读取数据
BOOL ifAutoLogin = [[NSUserDefaults standardUserDefaults]boolForKey:@"auto_login"];
NSString *userName = [[NSUserDefaults standardUserDefaults]objectForKey:@"userName"];
NSLog(@"%@",userName);
NSLog(@"%d",ifAutoLogin);
使用这种方式,数据都是存在了Library目录下的Preference子目录中的
2、plist:
// 获得Documents目录下plist文件的目录
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingString:@"/nineteen.plist"];
// 创建需要存储的对象
NSMutableArray *arrayM = [NSMutableArray array];
[arrayM addObject:@"nineteen1"];
[arrayM addObject:@"nineteen2"];
// 将对象写入到指定路径中去(NSArray、NSDictionary、NSString、NSNumber、NSData以及其中一些类型的可变类型)
[arrayM writeToFile:path atomically:YES];
// 从文件中读取文件
NSMutableArray *arrayM1 = [[NSMutableArray alloc]initWithContentsOfFile:path];
NSString *string1 = arrayM1[0];
NSString *string2 = arrayM1[1];
NSLog(@"string1 :%@ string2 :%@",string1,string2);
新建一个Student类继承于NSObject,然后在Student.h文件中定义:
#import <Foundation/Foundation.h>
// 如果一个类要进行编码和解码,就要实现NSCoding里面的两个方法,下面先遵守NSCoding的协议
@interface Student : NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
接着是Student.m文件:#import "Student.h"
@implementation Student
// 这个方法是在每次进行编码归档的时候调用
- (void)encodeWithCoder:(NSCoder *)aCoder
{
// 如果父类实现了NSCoding方法,那么就需要调用下super的方法
// 下面代表表示如何归档编码
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
// 这个方法是在每次进行解码恢复对象的时候调用
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
// 如果父类实现了NSCoding的方法,那么就需要调用下super的方法
// 下面表示如何解码恢复,但是要注意和encodeWithCoder方法中的归档编码方式相同
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
return self;
}
@end
最后在其他类中使用Student对象进行归档和恢复操作: // 归档路径
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingString:@"/nineteen.archive"];
// 创建对象
Student *student = [[Student alloc]init];
student.name = @"nineteen";
student.age = 19;
// 进行归档编码
[NSKeyedArchiver archiveRootObject:student toFile:path];
// 进行解码恢复
Student *student1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@",student1);
NSLog(@"%@ %ld",student1.name,(long)student1.age);