归档是一种对象都可以实现的更加常规的序列化方式。适用对模型对象进行归档的技术可以轻松将复杂对象写入文件和从文件中进行读取。大多数支持存储数据的Foundation和Cocos Touch类都遵循NSCoding协议(不过有些例外,例如UIIamge),因此对于大多数系统提供的类而言,归档比较轻松。如果是自定义的类,则需要自己实现NSCoding协议的编码和解码方法。下面还是用上篇文章中的例子,但是换成归档的方式进行持久化。
1、创建数据模型
创建类BIDFourLines,继承NSObject,定义有个NSArray类型的属性用来存储4个文本字段中的字符串。
#import <Foundation/Foundation.h>
@interface BIDFourLines : NSObject<NSCoding,NSCopying>
@property (nonatomic, copy) NSArray * lines;
@end
注意我们让它遵循了NSCoding和NSCopy协议,下面分别实现两个协议中的方法。
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.lines = [aDecoder decodeObjectForKey:@"lines"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.lines forKey:@"lines"];
}
-(id)copyWithZone:(NSZone *)zone
{
BIDFourLines * copy = [BIDFourLines allocWithZone:zone];
NSMutableArray * array = [NSMutableArray array];
if (copy) {
for (id line in self.lines) {
[array addObject:[line copy]];
}
}
copy.lines = array;
return copy;
}
对于任何数据模型,实现NSCopy协议都是非常有用的,通过它可以拷贝一个完全相同的对象。在copyWithZone方法中,我们创建了一个新的实例,并为它的属性设置相同的值。
2、实现ViewController
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic, strong) IBOutletCollection(UITextField)NSArray * lineFields;
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if ([[NSFileManager defaultManager] fileExistsAtPath:[self getFilePath]]) {
NSMutableData * data = [NSData dataWithContentsOfFile:[self getFilePath]];
NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSArray * array = [unarchiver decodeObjectForKey:@"hahaha"];
[unarchiver finishDecoding];
for (int i = 0; i<self.lineFields.count; i++) {
UITextField * textField = self.lineFields[i];
textField.text = array[i];
}
}
/*注册通知*/
NSNotificationCenter * center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (NSString *)getFilePath
{
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDirectory = paths[0];
NSString * dataPath = [documentDirectory stringByAppendingPathComponent:@"textFeildText.archive"];
return dataPath;
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
NSArray * textArray = [self.lineFields valueForKey:@"text"];
NSMutableData * data = [[NSMutableData alloc] init];
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:textArray forKey:@"hahaha"];
[archiver finishEncoding];
[data writeToFile:[self getFilePath] atomically:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
@end
当前viewController展现时,首先判断指定路径下有无归档文件,如果有,从归档文件中创建data实例,并创建一个NSKeyedUnarchiver进行解码。
值得注意的时,对数组或者字典进行归档时,要确保数组或字典中的元素也同时要遵循NSCoding协议,只有这样,其中的对象才可以和数组本身一起写入到文件当中,然后从文件中读取出来重新回到数组或字典当中。