从@encoded类型字符串解码类

时间:2013-08-10 11:43:30

标签: objective-c objective-c-runtime

Objective-C' s @encode生成C字符串来表示任何类型,包括基元和类,如下所示:

NSLog(@"%s", @encode(int));       // i
NSLog(@"%s", @encode(float));     // f
NSLog(@"%s", @encode(CGRect));    // {CGRect={CGPoint=ff}{CGSize=ff}}
NSLog(@"%s", @encode(NSString));  // {NSString=#}
NSLog(@"%s", @encode(UIView));    // {UIView=#@@@@fi@@I{?=b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b6b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b3b1b1b1b2b2b1}}

因此,我可以使用@encode(ClassName)获得一个有意义的类编码(包含类名称的编码),但它的格式与通用{{1}的编码格式相同(如上例所示)。

现在,我的问题是,给定任何(当然有效)类型编码,是否可以找出编码是否属于Objective-C类,如果是,则可以获取对应于该编码的struct对象?

当然,我可能可以尝试从类型编码中解析类名,并使用Class从中获取类,但这不是听起来像是正确的方式,或特别是性能效率。这真的是达到这个目标的最好方法吗?

2 个答案:

答案 0 :(得分:6)

不幸的是,我认为没有办法确定你正在使用编码的类。

dasblinkenlight在评论中有一个好主意,尽管他不支持其他实例变量。类的完整格式为{CLASSNAME=#IVARS}。但是,这也可能会捕获其他结构,我将在下面解释。

类的编码原因是它们被@encode处理为结构。 {表示结构的开始,后跟结构的名称和等号,然后是内容,最后是}。所有类在等号后面都有#的原因是类结构中的第一个元素是Class类型,这就是这种类型的编码方式。这意味着任何以Class开头的结构都会匹配此格式。如果列出了任何实例变量,它们将在#之后进行编码。例如,这是使用您发布的编码重构UIView。

Structure                         Encoding

struct UIView {                   {UIView=
    Class class1;                  #
    id id1, id2, id3, id4;         @@@@  Object pointers always encode as id.
    float float1;                  f
    int int1;                      i
    id id5, id6;                   @@
    unsigned int uint1;            I
    struct /*anonymous*/ {         {?=
        unsigned bitfield1 : 1;     b1   The type of bitfield is not encoded.
        unsigned bitfield2 : 1;     b1   I just chose unsigned.
        ...
        unsigned bitfield15 : 1;    b1
        unsigned bitfield16 : 6;    b6
        unsigned bitfield17 : 1;    b1
        ...
        unsigned bitfield58 : 1;    b1
        unsigned bitfield59 : 3;    b3
        unsigned bitfield60 : 1;    b1
        unsigned bitfield61 : 1;    b1
        unsigned bitfield62 : 1;    b1
        unsigned bitfield63 : 2;    b2
        unsigned bitfield64 : 2;    b2
        unsigned bitfield65 : 1;    b1
    };                             }
}                                 }

(使用/usr/include/objc/runtime.h中的_C_*常量进行解码)

如果您要将此结构放入代码中(填写... s),@encode(UIView)@encode(struct UIView)都会给您相同的结果。有趣的是,从技术上开始一个类的结构会使它成为一个有效的类类型,并且您可以成功地将消息发送到指向一个类的指针。但请注意,只有类接口中定义的实例变量才会放在编码中,因为其他位置的位置是在运行时确定的,因此不建议利用它来创建自己的对象。

答案 1 :(得分:1)

没有内置的方法可以做到这一点,但有几个人看到了解析@encode输出的逆向工程的潜力。我不拥有这个项目,但是nygard的class-dump可能会为您提供从@encode字符串中理解所需的一切。

相关问题