gpt4 book ai didi

objective-c - 启用 NSCoder 的类的简单方法

转载 作者:可可西里 更新时间:2023-11-01 03:35:26 25 4
gpt4 key购买 nike

我有大量的对象要保存以供离线使用。目前,我为对象和编码数据创建符合 NSCoder 标准的类以供离线使用。

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

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

然后在 .m 中进行初始化:

- (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 或键值编码进行编码和解码吗?基本上,我希望类中的所有变量都保存到文件中,并在程序启动时返回到对象中。这种方法可行,但创建所有类需要时间和精力。

最佳答案

是的,您可以自动执行此操作。首先将这些导入你的类:

#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. 这适用于数字、 bool 值、对象等属性,但自定义结构不起作用。此外,如果您的类中的任何属性是本身不支持 NSCoding 的对象,这将不起作用。

  2. 这仅适用于合成属性,不适用于 ivars。

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

更新:

我已将这些方法打包到一个库中:https://github.com/nicklockwood/AutoCoding - 该库将这些方法实现为 NSObject 上的一个类别,因此可以保存或加载任何类,并且它还添加了对编码继承属性的支持,我的原始答案没有处理。

更新 2:

我已经更新了正确处理继承和只读属性的答案。

关于objective-c - 启用 NSCoder 的类的简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8938018/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com