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; }