在开发过程中对自定义对象数据进行归档解档时候需要实现两个方法: encodeWithCoder和initWithEncoder。encodeWithCoder就是编码,initWithCoder就是解码。比如下面我自定义对象MyModel进行归档和解档。
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:[NSNumber numberWithInt:self.custId] forKey:kCUSTIDKey];
[aCoder encodeObject:[NSNumber numberWithInt:self.custStatusId] forKey:kCUSTSTATUSKey];
[aCoder encodeObject:self.phoneName forKey:kPHONEKey];
[aCoder encodeObject:self.houseName forKey:kHOUSENUMKey];
[aCoder encodeObject:self.nickName forKey:kNICKNAMEKey];
}
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.custId = [[aDecoder decodeObjectForKey:kCUSTIDKey] intValue];
self.custStatusId = [[aDecoder decodeObjectForKey:kCUSTSTATUSKey] intValue];
self.phoneName = [aDecoder decodeObjectForKey:kPHONEKey];
self.houseName = [aDecoder decodeObjectForKey:kHOUSENUMKey];
self.nickName = [aDecoder decodeObjectForKey:kNICKNAMEKey];
}
return self;
}
当对象的属性很多的时候,我们这样写简直是太繁琐了,有没有一种简便的方法少些重复的代码呢,答案当然有,利用objc runtime动态的获取对象的属性,并且采用KVC(key-value-coding)的方式实现归档和解档,比如:
/*
* Objective-C运行时库提供了非常便利的方法获取其对象运行时所属类及其所有成员变量,
* 并通过KVC进行值的存取,那么或者可以这样objc/runtime+KVC
*/
- (void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int count;
Ivar *ivar = class_copyIvarList([MyModel class], &count);
for (int i=0; i<count; i++) {
Ivar iv = ivar[i];
const char *name = ivar_getName(iv);
NSString *strName = [NSString stringWithUTF8String:name];
//利用KVC取值
id value = [self valueForKey:strName];
[aCoder encodeObject:value forKey:strName];
}
free(ivar);
}
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
unsigned int count = 0;
//获取类中所有成员变量名
Ivar *ivar = class_copyIvarList([MyModel class], &count);
for (int i=0; i<count; i++) {
Ivar iva = ivar[i];
const char *name = ivar_getName(iva);
NSString *strName = [NSString stringWithUTF8String:name];
//解档
id value = [aDecoder decodeObjectForKey:strName];
//利用KVC赋值
[self setValue:value forKey:strName];
}
free(ivar);
}
return self;
}
下面具体来看一个实例:
1、MyModel.h
//
// MyModel.h
// UseKVO
//
// Created by T-MAC on 15/4/19.
// Copyright (c) 2015年 T-MAC. All rights reserved.
//
#import <Foundation/Foundation.h>
#define kCUSTIDKey @"CUSTIDKey"
#define kCUSTSTATUSKey @"CUSTSTATUSKey"
#define kNICKNAMEKey @"NICKNAMEKey"
#define kHOUSENUMKey @"HOUSENUMKey"
#define kPHONEKey @"PHONEKey"
@interface MyModel : NSObject<NSCoding>{
int custId;
int custStatusId;
NSString *phoneName;
NSString *nickName;
NSString *houseName;
}
@property (nonatomic,assign) int custId;
@property (nonatomic,assign) int custStatusId;
@property (nonatomic,strong) NSString *phoneName;
@property (nonatomic,strong) NSString *nickName;
@property (nonatomic,strong) NSString *houseName;
+ (id)initWithCustId:(int)custId withStatusId:(int)statusId withPhoneName:(NSString *)phone withNickName:(NSString *)nickName withHouseName:(NSString *)houseName;
- (NSString *)description;
@end
2、MyModel.m
//
// MyModel.m
// UseKVO
//
// Created by T-MAC on 15/4/19.
// Copyright (c) 2015年 T-MAC. All rights reserved.
//
#import "MyModel.h"
#import <objc/runtime.h>
@implementation MyModel
@synthesize custId;
@synthesize custStatusId;
@synthesize phoneName;
@synthesize houseName;
@synthesize nickName;
+ (id)initWithCustId:(int)custId withStatusId:(int)statusId withPhoneName:(NSString *)phone withNickName:(NSString *)nickName withHouseName:(NSString *)houseName{
MyModel *mode = [[self alloc] init];
if (mode) {
mode.custId = statusId;
mode.custStatusId = statusId;
mode.phoneName = phone;
mode.nickName = nickName;
mode.houseName = houseName;
}
return mode;
}
/*
*不使用runtime+kvc
*/
//- (void)encodeWithCoder:(NSCoder *)aCoder{
// [aCoder encodeObject:[NSNumber numberWithInt:self.custId] forKey:kCUSTIDKey];
// [aCoder encodeObject:[NSNumber numberWithInt:self.custStatusId] forKey:kCUSTSTATUSKey];
// [aCoder encodeObject:self.phoneName forKey:kPHONEKey];
// [aCoder encodeObject:self.houseName forKey:kHOUSENUMKey];
// [aCoder encodeObject:self.nickName forKey:kNICKNAMEKey];
//}
//
//- (id)initWithCoder:(NSCoder *)aDecoder{
// self = [super init];
// if (self) {
// self.custId = [[aDecoder decodeObjectForKey:kCUSTIDKey] intValue];
// self.custStatusId = [[aDecoder decodeObjectForKey:kCUSTSTATUSKey] intValue];
// self.phoneName = [aDecoder decodeObjectForKey:kPHONEKey];
// self.houseName = [aDecoder decodeObjectForKey:kHOUSENUMKey];
// self.nickName = [aDecoder decodeObjectForKey:kNICKNAMEKey];
// }
// return self;
//
//}
/*
* Objective-C运行时库提供了非常便利的方法获取其对象运行时所属类及其所有成员变量,
* 并通过KVC进行值的存取,那么或者可以这样objc/runtime+KVC
*/
- (void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int count;
Ivar *ivar = class_copyIvarList([MyModel class], &count);
for (int i=0; i<count; i++) {
Ivar iv = ivar[i];
const char *name = ivar_getName(iv);
NSString *strName = [NSString stringWithUTF8String:name];
//利用KVC取值
id value = [self valueForKey:strName];
[aCoder encodeObject:value forKey:strName];
}
free(ivar);
}
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
unsigned int count = 0;
//获取类中所有成员变量名
Ivar *ivar = class_copyIvarList([MyModel class], &count);
for (int i=0; i<count; i++) {
Ivar iva = ivar[i];
const char *name = ivar_getName(iva);
NSString *strName = [NSString stringWithUTF8String:name];
//解档
id value = [aDecoder decodeObjectForKey:strName];
//利用KVC赋值
[self setValue:value forKey:strName];
}
free(ivar);
}
return self;
}
- (NSString *)description{
NSString *resStr = [NSString stringWithFormat:@"self.custid = %d,self.custStatusId = %d,self.phonename = %@,self.nickname = %@,self.housename = %@",self.custId,self.custStatusId,self.phoneName,self.nickName,self.houseName];
return resStr;
}
@end
3、存储自定义对象到文件验证归档、解档是否成功
//1.创建自定义对象
MyModel *mode = [MyModel initWithCustId:1 withStatusId:100 withPhoneName:@"apple" withNickName:@"json" withHouseName:@"white house"];
//2.获取文件路径
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *path=[docPath stringByAppendingPathComponent:@"person.yangyang"];
//3.写入文件---归档
[NSKeyedArchiver archiveRootObject:mode toFile:path];
//4.取出文件---接档
MyModel *retMode = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"retMode === %@",retMode);
从打印的结果看到,采用此方法成功的实现了归档和解档。