简单的方法来做NSCoder启用类

我有很多的对象,我想保存离线使用。 目前我使用创buildNSCoder兼容的类对象和编码数据文件可脱机使用。

所以在.h中我介绍这些对象:

@interface MyClass : NSObject<NSCoding>{ NSNumber* myObject;} @property(nonatomic,retain) NSNumber* myObject; 

在.m我做inits:

 - (id) initWithCoder: (NSCoder *)coder { if (self = [super init]) { [self setMyObject: [coder decodeObjectForKey:@"myObject"]]; } } - (void) encodeWithCoder: (NSCoder *)coder { [coder encodeObject: myObject forKey:@"myObject"]; } 

所以这个类只是存储getter和setter的虚拟存储。 这里有更好的方法来解码/编码。 我可以使用@dynamic或Key-value编码进行编码和解码吗? 基本上我想在程序启动时把所有类中的variables保存到文件中并返回到对象。 这种方法工作,但创build所有类需要时间和精力。

是的,你可以自动做到这一点。 首先将它们导入你的课堂:

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

你必须小心一点。 有以下警告:

  1. 这将适用于数字,布尔,对象等属性,但自定义结构将无法正常工作。 此外,如果您的类中的任何属性是不自己支持NSCoding的对象,这将无法正常工作。

  2. 这将只适用于合成的属性,而不是ivars。

您可以在编码之前通过检查encodeWithCoder中的值的types来添加error handling,或者覆盖setValueForUndefinedKey方法以更优雅地处理问题。

更新:

我已经将这些方法包装到一个库中: https : //github.com/nicklockwood/AutoCoding – 库实现这些方法作为NSObject的一个类别,因此任何类都可以被保存或加载,并且还增加了对inheritance编码的支持属性,我原来的答案不处理。

更新2:

我更新了正确处理inheritance和只读属性的答案。