NSCoding 是一个简单的协议,只有有两个方法:-initWithCoder: 和 encodeWithCoder:。遵循NSCoding协议的类可以被序列化(编码)和反序列化(解码),这样可以归档到磁盘上或分发到网络上。
自定义的类 只需要遵循NSCoding 协议并实现其两个方法就能使用NSKeyedArchiver和NSKeyedUnarchiver就行归档解档
自定义Book类遵循NSCoding协议:
@interface Book : NSObject <NSCoding>
@property (nonatomic , copy) NSString *title;
@property (nonatomic , copy) NSString *author;
@property (nonatomic , assign) NSUInteger pageCount;
@property (nonatomic , strong) NSSet *categories;
@property (nonatomic , assign,getter = isAvailable) BOOL available;
@end
@implementation Book
#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
self.title = [decoder decodeObjectForKey:@title];
self.author = [decoder decodeObjectForKey:@author];
self.pageCount = [decoder decodeIntegerForKey:@pageCount];
self.categories = [decoder decodeObjectForKey:@categories];
self.available = [decoder decodeBoolForKey:@available];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.title forKey:@title];
[encoder encodeObject:self.author forKey:@author];
[encoder encodeInteger:self.pageCount forKey:@pageCount];
[encoder encodeObject:self.categories forKey:@categories];
[encoder encodeBool:[self isAvailable] forKey:@available];
}
@end
使用NSKeyedArchiver和NSKeyedUnarchiver就行归档解档
-(IBAction)save {
1.新的模型对象
Book*book=[[Bookalloc]init];
book.title=@狂人日记;
book.author=@鲁迅;
book.pageCount = 30;
book.categories = [[NSSet alloc] initWithObjects:@1, @2, @3, nil ];
book.available = YES;
//2.归档模型对象
//2.1.获得Documents的全路径
NSString *doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) lastObject];
//2.2.获得文件的全路径
NSString*path=[docstringByAppendingPathComponent:@book.data];
//2.3.将对象归档 存储到沙盒
[NSKeyedArchiverarchiveRootObject:booktoFile:path];
}
- (IBAction)read {
//1.获得Documents的全路径
NSString*doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) lastObject];
//2.获得文件的全路径
NSString*path=[doc stringByAppendingPathComponent:@book.data];
//3.从文件中读取book对象
Book*book= [NSKeyedUnarchiver unarchiveObjectWithFile:path];
}
扩展①:NSUserDefaults支持的数据类型【都是不可变的】有:NSNumber(NSInteger、float、double),NSString,NSDate,NSData,NSArray,NSDictionary,BOOL. 如果要存储自定义类型 需要转成NSData
Book*book=[[Bookalloc] init]; book.title = @呐喊; book.author = @鲁迅; book.pageCount = 60; book.categories = [[NSSet alloc] initWithObjects:@1, @2, @3, NSData *data = [[NSKeyedArchiver archivedDataWithRootObject:book]] //先转成NSData 再存储 NSData *data = [NSKeyedArchiver archivedDataWithRootObject:book]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:@book]; //取数据 NSData *myData = [[NSUserDefaults standardUserDefaults] objectForKey:@book]; Book *myBook = [NSKeyedUnarchiver unarchiveObjectWithData:myData]
扩展②:利用runtime更加高效的进行归档解决档
///归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count;
// 获得指向当前类的所有属性的指针
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
// 获取指向当前类的一个属性的指针
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
NSString *propertyValue = [self valueForKeyPath:propertyName];
// 编码属性
[aCoder encodeObject:propertyValue forKey:propertyName];
}
free(properties);
}
///解档
- (id)initWithCoder:(NSCoder *)aDecoder {
if(self = [super init])
{
unsigned int count;
// 获得指向当前类的所有属性的指针
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
//解码属性
NSString *propertyValue = [aDecoder decodeObjectForKey:propertyName];
[self setValue:propertyValue forKey:propertyName];
}
free(properties);
}
return self;
}