关于type encodings的理解--runtime pro

作者: initlife | 来源:发表于2015-11-10 17:56 被阅读2593次

    runtime programming guide

    这次准备好好研究下runtime programming, 先从encodings开始了解,这个对于理解oc的类也是很有帮助的。
    废话不多说直接开始。

    Type Encodings

    compiler 编码encode 每个method的返回值,参数类型,将这些信息保存在一个字符串里。然后将这个string和selector关联起来。

    这套编码也适用于其他场景,所以这个@encode编译器指令是设计成公开的。当给定一个type的规范声明,@encode()返回相对应的字符串类型编码值。

    char *buf1 = @encode(int **);
    char *buf2 = @encode(struct key);
    char *buf3 = @encode(Rectangle);
    
    type encodings

    更多的类型可以查看https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1

    数组的type code是一个中括号里面,然后紧接着一个数组个数值和相对应的数组元素的类型,如一个包含12个float指针的数组的编码为:[12^f]

    structures 是一个大括号里,里面是显示紧跟着structure tag(struct的结构名称)然后一个等号(equal sign)=,接着就是struct里各个类型排列在一起,比如

    typedef struct example {
        id   anObject;
        char *aString;
        int  anInt;
    } Example;
    

    的type code值为 {example=@*i}, 如果是一个结构体的指针,那么encode为^{example=@*i},如果是一个结构体的指针的指针,则是^^{example}.

    Objects对象也被看成一个struct。@encode(NSObject)结果是{NSObject=#}, 因为NSObject class里就一个isa(class 类型)的变量。

    尽管 @encode()不直接返回数据, 但运行时会使用额外的一个encoding列表来表示一些方法声明的后缀修饰符.

    code Meaning
    r const
    i int
    N inout
    o out
    O bycopy
    R byref
    V oneway

    Declared Propertyies

    当编译器碰到property声明时,它会生成描述性的带有关于class, category或者protocol的metadata元数据。

    你能通过一些列的api函数来访问这个metadata,通过class,protocol上的name来查找property。可以通过@encode来获取property的encode string。可以copy property的attributes list(C strings)。

    class和protocol都有一个properties list的值。

    property type and functions

    可以通过class_copyPropertyList和protocol_copyPropertyList来遍历class(包括loaded categories)和protocol的property list

    通过property_getAttributes可以获取到一个property属性的@encode type的值。

    比如一个@property (nonatomic, strong) NSString *login;的property @encode值为T@"NSString",&,N,V_login

    每个逗号都是分割一个属性attribute,实际上当你获取到objc_property_attribute_t *attrs = property_copyAttributeList(prot, &outcount);(注意你还需要主动free掉attrs) outcount的值就是分割后的数组的个数。

    attrs分别为:

    property index name value
    0 T @"NSString"
    1 &
    2 N
    3 V _login

    Property type string

    文档里面有一段英文很重要,他描述了property type的string值的格式(这个值可以通过@encode或者通过property_getAttributes来获取)。

    You can use the property_getAttributes function to discover the name, the @encode type string of a property, and other attributes of the property.

    The string starts with a T followed by the @encode type and a comma, and
    finishes with a V followed by the name of the backing instance variable.
    Between these, the attributes are specified by the following descriptors, separated by commas:

    *** 这段英文很重要,说明了格式,首先是以一个T开头的,然后@encode type加一个逗号,以一个V后面带上存储支持的实例变量,然后在中间,每个attributes都是以逗号隔开的,这些attributes描述如下:***

    可以官场上面的那个例子@property (nonatomic, strong) NSString *login;的property @encode值为T@"NSString",&,N,V_login

    Table 7-1 Declared property type encodings

    Code Meaning
    R The property is read-only (readonly).
    C The property is a copy of the value last assigned (copy).
    & The property is a reference to the value last assigned (retain).
    N The property is non-atomic (nonatomic).
    G<name> The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,).
    S<name> The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,)
    D The property is dynamic (@dynamic).
    W The property is a weak reference (__weak).
    P The property is eligible for garbage collection.
    t<encoding> Specifies the type using old-style encoding.

    这个链接里有相关的demo示例说明property declaration声明和描述description。
    https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5

    这里只罗列少数几个:

    property declaration description
    @property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter; Ti,GintGetFoo,SintSetFoo:,V_intSetterGetter
    @property int intSynthEquals;In the implementation block:@synthesize intSynthEquals=_intSynthEquals; Ti,V_intSynthEquals
    @property int (*functionPointerDefault)(char *); T^?,V_functionPointerDefault
    @property (strong, atomic) NSString * dataObject; T@"NSString",&,V_dataObject

    function/method type encode

    先看例子:

    //- (void)viewWillAppear:(BOOL)animated  -> v20@0:8B16
    NSLog(@"%s", class_getInstanceMethod([self class], @selector(viewWillAppear:)));
    //- (void) setSomething:(id) anObject  -> v24@0:8@16
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:))));
    //- (BOOL) setSomething:(UInt8)animated aa:(id)anObject  -> B28@0:8C16@20
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
    //- (BOOL) setSomething:(UInt16)animated aa:(id)anObject  -> B28@0:8s16@20
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
    //- (BOOL) setSomething:(int)animated aa:(id)anObject  -> B28@0:8i16@20
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
    //- (BOOL) setSomething:(long)animated aa:(id)anObject-> B32@0:8q16@24
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
    
    
    typedef struct  {
        uint32_t a;
        uint16_t b;
        uint8_t c;
    } __attribute__((packed)) MyStruct;
    // - (void)strutMethod:(MyStruct)aa  -> v23@0:8{?=ISC}16
    NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(strutMethod:))));
    

    那么如何理解呢?

    • v means void return type
    • 20 means the size of the argument frame (20 bytes),整个方法参数占位的总长度
    • @0 means that there is an Objective-C object type at byte offset 0 of the argument frame (this is the implicit self object in each Objective-C method),这个表示在offset为0的地方有一个objective-c的对象,在objective-c method里,首个对象是self自身。
    • :8 means that there is a selector at byte offset 8 (this is the implicit _cmd in every method, which is the selector that was used to invoke the method). 在offset为8的地方有一个SEL,由于我测试的是64位机器上,所以之前的OC的对象指针占位8个字节。
    • B16 means 在offset 16的地方,有一个bool类型的参数,由于oc的对象和sel都是指针类型,64位机下所以都是占位8位,这里的bool也就出现在offset16的地方了。至于为什么bool参数占位了4个字节。主要原因是内存对齐的原因

    从上面看起来,不管是bool,uint8,uint16,int都被认为4个字节。因为他们的内存实际占位都小于4个字节,由于内存对齐原因所以实际最后占位为4字节。这里当你看最后一个MyStruct就可以看出,当主动告诉编译器取消结构体的内存对齐,就发现最后一个参数事迹展位是7(4+2+1)个字节

    注:packed属性:使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐.
    typedef struct  {
        uint32_t a;
        uint16_t b;
        uint8_t c;
    } __attribute__((packed)) MyStruct;
    

    未完待续

    至此先了解介绍完了关于type encodings, property type encodings,method encodings。稍后继续补充了解更多的运行时编程相关的知识点,runtime programming guide~~~.

    参考链接

    1. http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-April/036654.html

    相关文章

      网友评论

      • 我本善良:写的比较好,这个对理解runtime是基础,但个人认为也是很关键的
      • 杨淳引:从您的代码里学到了拿到method type encode的方法,但是我比较好奇什么情况下会出现method encodings表里面的那些code,就是rnNoORV这些?
        另外,您这个表和官方文档的有点出入:官方文档的表里面第2栏的code是n,meaning是in。

      本文标题:关于type encodings的理解--runtime pro

      本文链接:https://www.haomeiwen.com/subject/nwdhhttx.html