是的,您可以自动执行此操作。首先将这些导入您的课程:
#import <objc/runtime.h>
#import <objc/message.h>
现在添加这个方法,它将使用低级方法来获取属性名称:
- (NSArray *)propertyKeys
{
NSMutableArray *array = [NSMutableArray array];
Class class = [self class];
while (class != [NSObject class])
{
unsigned int propertyCount;
objc_property_t *properties = class_copyPropertyList(class, &propertyCount);
for (int i = 0; i < propertyCount; i++)
{
//get property
objc_property_t property = properties[i];
const char *propertyName = property_getName(property);
NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
//check if read-only
BOOL readonly = NO;
const char *attributes = property_getAttributes(property);
NSString *encoding = [NSString stringWithCString:attributes encoding:NSUTF8StringEncoding];
if ([[encoding componentsSeparatedByString:@","] containsObject:@"R"])
{
readonly = YES;
//see if there is a backing ivar with a KVC-compliant name
NSRange iVarRange = [encoding rangeOfString:@",V"];
if (iVarRange.location != NSNotFound)
{
NSString *iVarName = [encoding substringFromIndex:iVarRange.location + 2];
if ([iVarName isEqualToString:key] ||
[iVarName isEqualToString:[@"_" stringByAppendingString:key]])
{
//setValue:forKey: will still work
readonly = NO;
}
}
}
if (!readonly)
{
//exclude read-only properties
[array addObject:key];
}
}
free(properties);
class = [class superclass];
}
return array;
}
然后这里是你的 NSCoder 方法:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [self init]))
{
for (NSString *key in [self propertyKeys])
{
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
for (NSString *key in [self propertyKeys])
{
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
}
你必须小心一点。有以下注意事项:
这适用于数字、布尔值、对象等属性,但自定义结构不起作用。此外,如果您的类中的任何属性是本身不支持 NSCoding 的对象,则这将不起作用。
这仅适用于合成属性,不适用于 ivars。
您可以通过在编码之前检查 encodeWithCoder 中的值的类型来添加错误处理,或者覆盖 setValueForUndefinedKey 方法以更优雅地处理问题。
更新:
我已将这些方法包装到一个库中:https ://github.com/nicklockwood/AutoCoding - 该库将这些方法作为 NSObject 上的一个类别实现,因此可以保存或加载任何类,它还增加了对继承编码的支持属性,我原来的答案没有处理。
更新 2:
我已经更新了正确处理继承和只读属性的答案。