将NSObject的所有属性编码为NSData

时间:2012-05-22 15:20:34

标签: ios nsdata nsobject nscoding

所以我是iOS的新手,但我对一个简单任务的复杂性感到有点困惑。我正在尝试在NSUserDefaults中存储名为“Vehicle”的自定义NSObject类。显然,这是不可能的,所以我需要先将它编码为NSDATA。细

但这意味着我需要在解码中编码类的每个属性...

在我的车辆类......

- (void) encodeWithCoder: (NSCoder *) coder
{
    [coder encodeInt: x  forKey: @"x"];
    [coder encodeInt: y  forKey: @"y"];
    [coder encodeInt: direction  forKey: @"direction"];

} // encodeWithCoder

- (id) initWithCoder: (NSCoder *) coder
{
    if (self = [super init]) {
        x = [coder decodeIntForKey: @"x"];
        y = [coder decodeIntForKey: @"y"];
        direction = [coder decodeIntForKey: @"direction"];
    }

    return (self);

} // initWithCoder

如果我最终在车辆类中添加新属性,我也必须添加编码和解码逻辑。这与使用CopyWithZone创建类的副本相同。这留下了3或4个区域,在这些区域中向类中添加新属性可能会出错。

我目前主要在LabVIEW中编程,我们可以接受一个类,并将其提供给编码器,编码器将自动执行所有版本控制和属性操作。

所以我想我的问题是:

  1. 在iOS中没有听说过吗?
  2. 如果不可能,有没有办法枚举类中的所有属性并编写一个自动执行此操作的函数。

1 个答案:

答案 0 :(得分:1)

您可以使用objective-c运行时查找对象的所有属性并对其进行解码,但我不建议使用它。如果你有意思,我可以为你创建一个简单的例子。

编辑:这是一个例子:

#import <objc/runtime.h>

void decodePropertiesOfObjectFromCoder(id obj, NSCoder *coder)
{
    // copy the property list
    unsigned propertyCount;
    objc_property_t *properties = class_copyPropertyList([obj class], &propertyCount);

    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = properties[i];

        char *readonly = property_copyAttributeValue(property, "R");
        if (readonly)
        {
            free(readonly);
            continue;
        }

        NSString *propName = [NSString stringWithUTF8String:property_getName(property)];

        @try 
        {
            [obj setValue:[coder decodeObjectForKey:propName] forKey:propName];
        }
        @catch (NSException *exception) {
            if (![exception.name isEqualToString:@"NSUnknownKeyException"])
            {
                @throw exception;
            }

            NSLog(@"Couldn't decode value for key %@.", propName);
        }
    }

    free(properties);
}

void encodePropertiesOfObjectToCoder(id obj, NSCoder *coder)
{
    // copy the property list
    unsigned propertyCount;
    objc_property_t *properties = class_copyPropertyList([obj class], &propertyCount);

    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = properties[i];

        char *readonly = property_copyAttributeValue(property, "R");
        if (readonly)
        {
            free(readonly);
            continue;
        }

        NSString *propName = [NSString stringWithUTF8String:property_getName(property)];

        @try {
            [coder encodeObject:[obj valueForKey:propName] forKey:propName];
        }
        @catch (NSException *exception) {
            if (![exception.name isEqualToString:@"NSUnknownKeyException"])
            {
                @throw exception;
            }

            NSLog(@"Couldn't encode value for key %@.", propName);
        }
    }

    free(properties);
}

__attribute__((constructor))
static void setDefaultNSCodingHandler()
{
    class_addMethod([NSObject class], @selector(encodeWithCoder:), imp_implementationWithBlock((__bridge void *)[^(id self, NSCoder *coder) {
        encodePropertiesOfObjectToCoder(self, coder);
    } copy]), "v@:@");
    class_addMethod([NSObject class], @selector(initWithCoder:), imp_implementationWithBlock((__bridge void *)[^(id self, NSCoder *coder) {
        if ((self = [NSObject instanceMethodForSelector:@selector(init)](self, @selector(init))))
        {
            decodePropertiesOfObjectFromCoder(self, coder);
        }

        return self;
    } copy]), "v@:@");
}

这允许您对公开足够属性的任何对象进行编码以重构自身。