简介
- 文件归档 — 就是把需要存储的对象数据存储到磁盘上,实现数据的持久性存储和备份
- 解档 — 就是从磁盘上读取该文件下的数据
iOS 本地存储方法:plist属性列表,归档,SQLite,CoreData
本篇文章对归档和解档进行介绍,其他方法日后学习。
对象归档是将对象以文件(二进制数据)的形式保存到磁盘中(也称为序列化,持久化),使用的时候读取该文件的保存路径,从而读取文件的内容(也称为接档,反序列化)
对象归档的文件是保密的,在磁盘上无法查看文件中的内容,而属性列表是明文的,可以查看。通过文件归档产生的文件是不可见的,如果打开归档文件的话,内容是乱码的;ta不同于属性列表和plist文件是可见的,正因为不可见的缘故,使得这种持久性的数据保存更有可靠性
这是序列化某个自定义对象后的文件内容:
自定义对象的单个对象归档、解档
对自定义的单个对象进行归档和解归档(由于自定义对象不具有归档的性质,所以要实现归档和解归档,首先必须实现NSCoding 协议
)
- 自定义一个Person类并实现
NSCoding 协议
的方法
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy)NSString* name;
@property (nonatomic, assign)int age;
@property (nonatomic, assign)double weight;
//@property (nonatomic, strong)Dog* dog;
@end
@implementation Person
//NSCoder是一个抽象类
//归档的协议方法
//将归档对象协议化
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject: self.name forKey: @"name"];
[coder encodeInt: self.age forKey: @"age"];
[coder encodeDouble: self.weight forKey: @"weight"];
//[coder encodeObject: self.dog forKey: @"dog"];
}
//解档的协议方法
//将解档对象反序列化
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
self.name = [coder decodeObjectForKey: @"name"];
self.age = [coder decodeIntForKey: @"age"];
self.weight = [coder decodeDoubleForKey: @"weight"];
//self.dog = [coder decodeObjectForKey: @"dog"];
}
return self;
}
@end
- 初始化待归档对象并进行归档
void archiveTest(void) {
Person* person = [[Person alloc] init];
person.name = @"XY";
person.age = 20;
person.weight = 125.0;
// Dog* dog = [[Dog alloc] init];
// dog.name = @"Oudy";
// person.dog = dog;
BOOL isSuccess = [NSKeyedArchiver archiveRootObject: person toFile: @"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt"];
if (isSuccess) {
NSLog(@"归档成功");
} else {
NSLog(@"归档失败");
}
}
归档文件名称和路径自己随意设置
根据归档方法返回的BOOL
值对归档的成功与否进行一个判断
- 归档后开始解档
int main(int argc, const char * argv[]) {
@autoreleasepool {
//成功归档后,注释掉
//archiveTest();
//解档此文件
Person* person = [NSKeyedUnarchiver unarchiveObjectWithFile: @"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt"];
NSLog(@"%@ %d %f", person.name, person.age, person.weight);
//NSLog(@"%@ %d %f %@", person.name, person.age, person.weight, person.dog.name);
}
return 0;
}
可以看到成功从本地文件中读取出已存储的对象数据
在以上过程中,可以看到本人注释掉的自定义类Dog的dog属性,这是为了说明如果存在有嵌套类(复合类),那么内层的类也需要实现NSCoding 协议
,否则程序会崩溃,如下
@interface Dog : NSObject <NSCoding>
@property (nonatomic, copy)NSString* name;
@end
@implementation Dog
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject: self.name forKey: @"name"];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
self.name = [coder decodeObjectForKey: @"name"];
}
return self;
}
@end
多个对象归档、解档
以上的做法中,一个文件仅归档一个对象,对于大工程量的项目这样做肯定是极其耗费时间及精力的
接下来来看如何将多个对象归档到一个文件里去
使用数组
- 我们可以用数组存储多个对象,然后将数组这一对象进行归档和解档
void archiveTest(void) {
Person* person1 = [[Person alloc] init];
person1.name = @"XY";
person1.age = 20;
person1.weight = 125.0;
Person* person2 = [[Person alloc] init];
person2.name = @"ZA";
person2.age = 19;
person2.weight = 130.0;
Person* person3 = [[Person alloc] init];
person3.name = @"BC";
person3.age = 21;
person3.weight = 135.0;
NSArray* array = @[person1, person2, person3];
BOOL isSuccess = [NSKeyedArchiver archiveRootObject: array toFile: @"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt"];
if (isSuccess) {
NSLog(@"归档成功");
} else {
NSLog(@"归档失败");
}
}
- 进行解归档(归档时,如果目标文件之前存有数据,那么新的归档数据会将原文件完全覆盖)
int main(int argc, const char * argv[]) {
@autoreleasepool {
//成功归档后,注释掉
//archiveTest();
//解档
NSArray* array = [NSKeyedUnarchiver unarchiveObjectWithFile: @"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt"];
for (Person* person in array) {
NSLog(@"%@ %d %f", person.name, person.age, person.weight);
}
}
return 0;
}
结果如下:
解档成功!
多对象归档和解档
上个方法是将多个对象转化成一个对象进行归档解档,实际上还是针对单个对象进行操作,局限性仍然很大,下面介绍多对象归档和解档
- 初始化多个对象数据并进行归档
void archiveTest(void) {
Person* person1 = [[Person alloc] init];
person1.name = @"XY";
person1.age = 20;
person1.weight = 125.0;
Person* person2 = [[Person alloc] init];
person2.name = @"ZA";
person2.age = 19;
person2.weight = 130.0;
Person* person3 = [[Person alloc] init];
person3.name = @"BC";
person3.age = 21;
person3.weight = 135.0;
NSMutableData* data = [NSMutableData data];
//根据二进制流创建归档对象
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data];
//对对象进行归档操作
[archiver encodeObject: person1 forKey: @"person1"];
[archiver encodeObject: person2 forKey: @"person2"];
[archiver encodeObject: person3 forKey: @"person3"];
//结束归档
[archiver finishEncoding];
BOOL isSuccess = [data writeToFile:@"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt" atomically: YES];
if (isSuccess) {
NSLog(@"归档成功");
} else {
NSLog(@"归档失败");
}
}
- 对多个对象进行解档
int main(int argc, const char * argv[]) {
@autoreleasepool {
//成功归档后,注释掉
//archiveTest();
NSData* data = [NSData dataWithContentsOfFile: @"/Users/jakey/Desktop/CS/Xcode/解档和归档/archiveTest.txt"];
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];
Person* person1 = [unarchiver decodeObjectForKey: @"person1"];
Person* person2 = [unarchiver decodeObjectForKey: @"person2"];
Person* person3 = [unarchiver decodeObjectForKey: @"person3"];
[unarchiver finishDecoding];
NSLog(@"%@ %d %f", person1.name, person1.age, person1.weight);
NSLog(@"%@ %d %f", person2.name, person2.age, person2.weight);
NSLog(@"%@ %d %f", person3.name, person3.age, person3.weight);
}
return 0;
}
运行结果
这样就实现了对多个对象进行解档和归档!
归档在开发中的简单应用例子
我们日常使用微博时,刷到某个页面的某个位置然后退出并关闭应用,然后断开网络重新打开微博,仍会显示上次的界面,这就是因为程序将这个页面的数据进行了归档,缓存在了本地,打开时进行解档就会显示原页面
不这样做的话,再次打开页面就会显示空白页面,影响用户体验