1.归档的基本概念
- 归档: 是指将数据写入文件存储到程序的沙盒中,当再次重新打开程序时,可以还原这些数据. 称它为数据序列化, 数据持久化. 临时数据: 存储在内存中的数据, 程序关闭, 内存释放,数据丢失
- 数据持久性的方式
1) NSKeyedArchiver—-对象归档
2) NSUserDefaults
3) 属性列表化(NSArray, NSDictionaty保存文件)
4) SQlite数据库, Core Data数据库 - 归档的形式
1) 对Foundation库中对象进行归档
2) 自定义对象进行归档(需要实现归档协议, NSCoding) - 归档后的文件是加密的,属性列表是明文的.
- 归档
1) 使用NSData实例作为归档的存储数据
2) 添加归档的内容(设置key与value)
3) 完成归档
4) 将归档数据存入磁盘中 - 解归档
1) 从磁盘读取文件, 生成NSData实例
2) 根据Data实例创建和初始化解归档实例
3) 解归档, 根据key访问value的值 - 苹果手机为了保证自己数据上的绝对的安全,设计了沙盒文件(其中有三个文件Documents,Library,tmp),每一个应用程序都配备了自己的沙盒文件,每一次运行,文件夹的名字就会变成一个没有任何规律的字符串
- 通过数组获取沙盒路径的方法有三个参数:1). 当前要前往哪一个文件夹,前往documents文件用NSDocumentDirectory,前往caches文件用NSCachesDirectory 2). 访问的文件夹的类型,指定访问是用户文件夹 3). 绝对路劲(YES),相对路劲(NO)–绝对路劲是给系统来使用的,系统可以根据当前的路劲找到文件夹.我们在操作文件的时候都是用绝对路劲,相对路劲只会把要前往的文件夹现实,其他的部分都是~,告诉程序员要去那个文件夹
- 沙盒(本质是一个文件夹,名字随机分配)里一共有三个文件:
1) Documents文件是要是用来存储用户想要存储的一些信息,比如收藏的信息或者自己设置的一些内容,比如我们做的收藏功能就是往这个文件夹里写
2) Library文件夹是方便程序开发者使用的,主要操作它里面的两个文件夹,caches和Preferences. caches:用来保存缓存文件,SDWebImage会把图片加载到缓存文件中,所以清除缓存功能就是把这个文件夹删除.Preferences一般用来保存程序员设置的信息,比如NSUserDefaults就会把数据保存到这个文件夹中
3) tmp文件一般存放临时内容,之前版本还有一个.app文件
2.第一种归档方式
main.m文件
**归档对象**
NSString *homepath = NSHomeDirectory();
NSString *path = [homepath stringByAppendingPathComponent:@"archiver2.plist"];
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
NSArray *array = @[@"zhangsam",@"liuyang"];
[archiver encodeObject:array forKey:@"name"];
[archiver encodeInt:100 forKey:@"number"];
[archiver finishEncoding];
BOOL success = [data writeToFile:path atomically:YES];
if (success) {
NSLog(@"success");
}
***解归档***
NSString *homepath = NSHomeDirectory();
NSString *path = [homepath stringByAppendingPathComponent:@"archiver2.plist"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
int number = [unArchiver decodeIntForKey:@"number"];
NSArray *array = [unArchiver decodeObjectForKey:@"name"];
NSLog(@"\n %d %@",number,array);
3.把简单对象写入到本地,简单对象指的是NSString,NSArray,NSDictionary,NSData
//先通过数组获取沙盒路劲,然后从数组里获取沙盒路径
NSArray *sandBox = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *sandBoxPath = sandBox[0];
//要给写入的文件拼接一个路径,拼接方式有两种,一般用后面路径专有方法
//NSString *documentPath = [sandBoxPath stringByAppendingString:@"/古玉.txt"];
NSString *documentPath = [sandBoxPath stringByAppendingPathComponent:@"古玉.txt"];
NSString *str = @"隔壁老顾爱耍贱";
//把字符串写入到本地,如果路劲下有对应文件,则会把原来的文件覆盖掉,没有则新建一个文件
[str writeToFile:documentPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
//把沙盒文件再读取出来(解归档)
NSString *tempStr = [NSString stringWithContentsOfFile:documentPath encoding:NSUTF8StringEncoding error:nil];
//把数组写入到本地
NSArray *arr = @[@"1",@"2",@"3"];
//通过数组获取沙盒路径
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *str = [documentPath[0] stringByAppendingPathComponent:@"xiyi.plist"];
[arr writeToFile:str atomically:YES];
//把数组再读出来
NSArray *array = [NSArray arrayWithContentsOfFile:str];
4.把复杂对象(在Foundation框架内不存在的数据类)写入到本地,自定义归档
1) 自定义的对象要支持归档, 需要实现NSCoding协议
2) NSCoding协议有两个方法, encodeWithCoder 方法对对象的属性数据做编码处理. initWithCoder 解码归档数据来初始化对象
3) 实现NSCoding协议后,就能通过NSKeyArchiver归档.
4.)复杂对象无法通过writeToFile:方法进行数据持久化, 能通过将复杂对象转换为NSData, 然后通过writeToFile:进行数据持久化
Student.m和Student.h文件
#import <Foundation/Foundation.h>
#pragma mark 实现归档和反归档就得签订NSCoding协议
@interface Student : NSObject<NSCoding>
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *sex;
@property(nonatomic,assign)NSInteger age;
@property(nonatomic,copy)NSString *hobby;
- (instancetype)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age hobby:(NSString *)hobby;
+ (instancetype)studentWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age hobby:(NSString *)hobby;
@end
#import "Student.h"
@implementation Student
#pragma mark 需要实现两个必须实现的协议方法,归档和反归档
//对属性编码,归档的时候会调用
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInteger:_age forKey:@"age"];
[aCoder encodeObject:_hobby forKey:@"hobby"];
[aCoder encodeObject:_sex forKey:@"sex"];
//使用encode方法要和数据类型相互匹配
}
//对属性解码,解归档的时候调用
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.hobby = [aDecoder decodeObjectForKey:@"hobby"];
_age = [aDecoder decodeIntegerForKey:@"age"];
self.sex = [aDecoder decodeObjectForKey:@"sex"];
}
return self;
}
- (instancetype)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age hobby:(NSString *)hobby
{
self = [super init];
if (self) {
self.name = name;
self.sex = sex;
_age = age;
self.hobby = hobby;
}
return self;
}
+ (instancetype)studentWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age hobby:(NSString *)hobby
{
Student *student = [[Student alloc] initWithName:name sex:sex age:age hobby:hobby];
return student;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"name = %@, sex = %@, hobby = %@, age = %ld", _name,_sex,_hobby,_age];
}
- (void)dealloc
{
[_name release];
[_hobby release];
[_sex release];
[super dealloc];
}
@end
在ViewController.m文件里归档/解档操作
//复杂对象写入到本地,主要是指我们自己创建的对象写入到本地,也叫归档和反归档操作
Student *stu = [Student studentWithName:@"张三" sex:@"男" age:22 hobby:@"耍贱"];
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//拼接路径,扩展名可以是任意的
NSString *path = [documentPath[0] stringByAppendingPathComponent:@"student.plist"];
//对对象进行归档操作,两个参数:1.归档的对象 2.路径
[NSKeyedArchiver archiveRootObject:stu toFile:path];
//反归档
Student *strdent = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@",strdent);
//复杂对象放到数组里然后写入到本地
Student *stu1 = [Student studentWithName:@"张三1" sex:@"男" age:22 hobby:@"耍贱1"];
Student *stu2 = [Student studentWithName:@"张三2" sex:@"男" age:22 hobby:@"耍贱2"];
Student *stu3 = [Student studentWithName:@"张三3" sex:@"男" age:22 hobby:@"耍贱3"];
NSArray *arr = @[stu1,stu2,stu3];
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *stuPath = [documentPath[0] stringByAppendingPathComponent:@"student.plist"];
[NSKeyedArchiver archiveRootObject:arr toFile:stuPath];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:stuPath];
for (Student *stu in array) {
NSLog(@"%@",stu);
}
5.归档小结和NSFileManager
#pragma mark 总结:数据持久化的步骤
// 1.指定前往哪一个文件夹 2.用字符串接受路径 3.拼接文件路径 4.写入本地或者归档操作
// 注:如果是复杂对象归档,要签订NSCoding协议且实现两个协议方法,方在数组的复杂对象也要签协议
//NSUserDefaults一般存放的是小的数据(保存在Library/Preferences文件下),比如字符串,用法和字典类似
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"123456" forKey:@"password"];
//在从本地取值的方法和字典类似
NSLog(@"%@",[defaults objectForKey:@"password"]);
//创建一个文件管理者,通过文件管理者对文件夹进行操作
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *documentPaht = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//给要创建的文件夹拼接一个路径,文件夹名不需要任何的扩展名
NSString *filePath = [documentPaht[0] stringByAppendingPathComponent:@"guyu"];
//通过manager进行文件夹的创建
[manager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
//通过manager进行文件夹的删除
[manager removeItemAtPath:filePath error:nil];