开发中少不了用到NSKeyedArchiver归档和解档,之前我是这么写的:
//NSCoding实现
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.ID forKey:@"ID"];
}
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
self.ID = [aDecoder decodeObjectForKey:@"ID"];
self.name = [aDecoder decodeObjectForKey:@"name"];
}
return self;
}
这样写很传统,但是如果遇到了归档100个属性呢?那不是完蛋了!?
自此出现这个问题之后,接触到了runtime中<objc/runtime.h>的Ivar,如下:
typedef struct objc_ivar *Ivar;
可见它是一个结构体指针,它定义对象的实例变量,包括类型和名字。包括@interface
大括号中的属性和@property
中的属性。这也就是它与objc_property_t
的区别。
<objc/runtime.h>中声明了
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
#######这个方法就是copy cls类中@interface中的成员变量和属性,将数量回传给outCount,返回值我们看到了,就是这个Ivar,是个结构体指针,指向了第一个属性结构体的首地址。
#######之后我们利用返回的ivars指针,配合ivar_getname()
方法去除字符串形式的变量名称转换成NSString作为key,便可以进行后续操作了
由于是copy操作,后续不要忘记free()
释放内存。
我们用运行时的方法实现无论多少属性都通用的归档方法:
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
[self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
}
free(ivars);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
[aCoder encodeObject:[self valueForKey:key] forKey:key];
}
free(ivars);
}
网友评论