我正在尝试实现一件棘手的事情:我所有的模型类都有其属性的自动 NSCoding 实现。这让我可以在我的类中添加和删除属性,并且不用担心丢失的东西未被编码/解码。(实际上,它也有其他用途,但这是主要思想)。
当使用 initWithCoder 从存档初始化我的对象时,感谢 Obj-C 运行时,我浏览了我的属性列表,并尝试直接将 ivars 分配给值。由于各种专横的原因,我不想通过 setter,因此 setValue:forKey: 是被禁止的。
有趣的问题,不是吗?我必须说我对 C 指针的微妙之处并不完全有信心......
这是代码:
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(class, &outCount);
for (unsigned int index = 0; index < outCount; index++) {
objc_property_t property = properties[index];
NSString *propertyNameString = [NSString stringWithUTF8String:property_getName(property)];
id value = [coder decodeObjectForKey:propertyNameString];
if (value == nil) {
continue;
}
const char *attributes = property_getAttributes(property);
NSString *typeAttribute = [[NSString stringWithUTF8String:attributes] substringWithRange:NSMakeRange(1, 1)];
const char *ivarName = [[@"_" stringByAppendingString:propertyNameString] UTF8String];
if ([typeAttribute isEqualToString:@"@"]) {
Ivar ivar = class_getInstanceVariable([self class], ivarName);
object_setIvar(self, ivar, value);
}
else if ([typeAttribute isEqualToString:@"d"]) {
double *doublePointer = getIvarPointer(self, ivarName);
*doublePointer = [value doubleValue];
}
else if ([typeAttribute isEqualToString:@"i"]) {
int *intPointer = getIvarPointer(self, ivarName);
*intPointer = [value intValue];
}
else if ([typeAttribute isEqualToString:@"c"]) {
char *charPointer = getIvarPointer(self, ivarName);
*charPointer = [value boolValue];
}
else if ([typeAttribute isEqualToString:@"Q"]) {
NSUInteger *uintegerPointer = getIvarPointer(self, ivarName);
*uintegerPointer = [value unsignedIntegerValue];
}
}
free(properties);
'getIvar' 函数看起来像这样(是的,我在对象类上使用 class_getInstanceVariable,因为 ARC 不允许使用 object_getInstanceVariable...):
static void* getIvarPointer(id object, char const *name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (!ivar) return 0;
return (unsigned char *)(__bridge void *)object + ivar_getOffset(ivar);
}
运行 Xcode 的静态分析器时,我收到一条警告“取消引用空指针(从变量 'doublePointer' 加载) ”。有趣的是,int 和 NSUInteger 出现了类似的消息,但现在似乎消失了……它从未出现在“char”中。
任何想法、建议或有见地的批评都将不胜感激。
我必须说,代码确实有效。我确实在我的对象类中自动解码了 double 和 int。但我想了解为什么静态分析器会告诉我这样的事情。