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
从中获取类,但这不是听起来像是正确的方式,或特别是性能效率。这真的是达到这个目标的最好方法吗?
答案 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
字符串中理解所需的一切。