【问题标题】:Objective-C Reflection for generic NSCoding implementation用于通用 NSCoding 实现的 Objective-C 反射
【发布时间】:2009-05-28 05:11:46
【问题描述】:

Objective-C 中是否有任何反射方法允许您通过检查对象的公共属性并生成 encodeWithCoder: 和 initWithCoder: 的通用实现来编写通用 NSCoding 实现。

我正在考虑类似XStream for Java 的东西,它允许使用反射来序列化和反序列化 Java 对象的通用方法。更好的方法可能是将属性标记为您想要序列化或瞬态的东西(如 Java 中的瞬态关键字)。

我一直在阅读 Archives and Serializations Programming Guide 上有关 Cocoa 的文档。我知道您希望对对象的序列化进行一些控制,但这通常是一个对称的过程,必须反转为序列化编码的内容以反序列化它似乎很奇怪。我是 DRY 的信徒(不要重复自己)。

【问题讨论】:

  • 所选答案链接到不再作为其答案存在的站点。请相应地更新所选答案。如果有帮助,我已经编写了允许您在此处询问的方法:stackoverflow.com/a/52735075/2057171

标签: iphone objective-c reflection serialization objective-c-runtime


【解决方案1】:

这不仅是可能的,而且我有一个朋友正在努力做到这一点。 (您可以查看他的blog about it here。)反射是使用Objective-C 2.0 Runtime Reference 中记录的Objective-C 运行时函数完成的。看看吧。

但是请注意,这只有在您想要保存所有实例变量的通用行为时才有效。不过,您可能不希望 NSView 保存它的超级视图;在这种情况下,通用情况将不起作用。

您可以通过为要保存的任何实例变量声明属性并将任何其他变量“隐藏”来区分要序列化的事物和不可序列化的事物,但这将属性的全部目的扭曲为一个小好处。我不会推荐它。

【讨论】:

    【解决方案2】:

    (我是 BJ Homer 评论中链接的博客文章的作者)。使用代码有几个注意事项:

    1. 目标类必须符合 KVC。如果您为您的 ivars 使用 Objective-C 2.0 属性,那么您已经准备就绪。否则,您需要确保您的类设置为正确响应 valueForKey: 和 setValue:forKey: 方法。
    2. 代码使用运行时中未记录的“功能”以递归方式使 ivar 类符合 NSCoding。编译时,几乎所有的输入信息 (AFAIK) 都会从代码中删除,但为了保存 ivars,它们 也必须符合 NSCoding。我发现如果 ivar 是一个对象并且我在其上调用 ivar_getTypeEncoding(),我会得到一个 c 字符串,它看起来像:{#IVAR_CLASS}(示例:{#NSString})。我所做的是获取 # 和 } 之间的字符串,使用 NSClassFromString 创建一个 Class 对象,然后对其进行递归。
    3. 此代码将保存所有 ivars。
    4. 使用风险自负(当然)

    我写这个主要是为了证明概念,在很多情况下这段代码会严重失败。例如,在对象 A 中有一个用于 B 的 ivar,而 B 有一个用于 A 的 ivar,然后使用代码序列化其中一个或另一个会(我相信)导致无限循环。

    尽管如此,我认为 Objective-C 甚至允许你做类似的事情,这真是太棒了。

    【讨论】:

      【解决方案3】:

      查看 RMModelObject:

      http://www.realmacforge.com/svn/trunk/RMModelObject/

      但是,请注意,ObjC 运行时的东西可以在 10.5 和模拟器中使用,但不能在实际的 iPhone 上使用。好不容易才发现。也许 OS 3.0 终于支持了,但我没有检查。

      【讨论】:

        【解决方案4】:

        今晚写这篇文章就是为了这个目的;不要忘记#import!这假设你的类中的所有@properties 都是 NSObject 形式,所以 NSNumber 而不是 float 等。

        #import <objc/runtime.h>
        
        -(id)initWithCoder:(NSCoder *)decoder {
            if (self = [super init]) {
                uint count;
                objc_property_t *properties = class_copyPropertyList(self.class, &count);
                for (int i = 0; i < count ; i++) {
                    const char* propertyName = property_getName(properties[i]);
                    NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
                    NSValue *value = [decoder decodeObjectForKey:key];
                    [self setValue:value forKey:key];
                }
                free(properties);
            }
            return self;
        }
        
        - (void)encodeWithCoder:(NSCoder *)encoder {
            uint count;
            objc_property_t *properties = class_copyPropertyList(self.class, &count);
            for (int i = 0; i < count ; i++) {
                const char* propertyName = property_getName(properties[i]);
                NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
                NSValue *value = [self valueForKey:key];
                [encoder encodeObject:value forKey:key];
            }
            free(properties);
        }
        

        【讨论】:

          猜你喜欢
          • 2015-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-24
          • 2012-01-09
          • 1970-01-01
          • 1970-01-01
          • 2010-11-09
          相关资源
          最近更新 更多