Runtime:isa原理分析

作者: 码小菜 | 来源:发表于2020-02-05 12:43 被阅读0次
    夜景

    目录
    一,正常存储
    二,位运算
    三,位域
    四,共用体
    五,NS_OPTIONS
    六,isa_t
    七,ISA_MASK

    一,正常存储

    1,实例代码

    // Person
    @interface Person : NSObject
    @property (nonatomic, assign, getter=isTall) BOOL tall;
    @property (nonatomic, assign, getter=isRich) BOOL rich;
    @property (nonatomic, assign, getter=isHandsome) BOOL handsome;
    @end
    
    @implementation Person
    @end
    
    // 使用
    Person *person = [Person new];
    person.tall = YES;
    person.rich = NO;
    person.handsome = YES;
    NSLog(@"%d---%d---%d", person.isTall, person.isRich, person.isHandsome);
    
    // 打印
    1---0---1
    

    2,说明

    系统会自动生成三个成员变量来存储这三个属性的值,每个成员变量占一个字节,三个成员变量就需要三个字节,下面我们换一种方式,用一个字节来存储这三个属性的值

    二,位运算

    1,实例代码

    //#define TallMask     0b00000001
    //#define RichMask     0b00000010
    //#define HandsomeMask 0b00000100
    #define TallMask     (1<<0)
    #define RichMask     (1<<1)
    #define HandsomeMask (1<<2)
    
    @implementation Person
    {
        /*
         占一个字节,默认值为0b00000000
         最后一位存储tall,倒数第二位存储rich,倒数第三位存储handsome
         */
        char _tallRichHandsome;
    }
    - (void)setTall:(BOOL)tall {
        if (tall) {
            /*
             将1存储到最后一位,其他位不变
              0000 0000
             |0000 0001
              ---------
              0000 0001
             */
            _tallRichHandsome |= TallMask;
        } else {
            /*
            将0存储到最后一位,其他位不变
             0000 0001
            &1111 1110
             ---------
             0000 0000
            */
            _tallRichHandsome &= ~TallMask;
        }
    }
    - (BOOL)isTall {
        /*
        取出最后一位的值,其他位置0
         0000 0001
        &0000 0001
         ---------
         0000 0001
        */
        return !!(_tallRichHandsome & TallMask);
    }
    - (void)setRich:(BOOL)rich {
        if (rich) {
            _tallRichHandsome |= RichMask;
        } else {
            _tallRichHandsome &= ~RichMask;
        }
    }
    - (BOOL)isRich {
        return !!(_tallRichHandsome & RichMask);
    }
    - (void)setHandsome:(BOOL)handsome {
        if (handsome) {
            _tallRichHandsome |= HandsomeMask;
        } else {
            _tallRichHandsome &= ~HandsomeMask;
        }
    }
    - (BOOL)isHandsome {
        return !!(_tallRichHandsome & HandsomeMask);
    }
    @end
    

    2,说明

    • 与(&):两个都是1结果才为1
    • 或(|):只要一个是1结果就为1
    • 取反(~):将所有位取反,1变0,0变1
    • 两次取反(!!):将char类型转为BOOL类型
    三,位域

    1,实例代码

    @implementation Person
    {
        // 占一个字节
        struct {
            char tall : 1;     // 占最后一位
            char rich : 1;     // 占倒数第二位
            char handsome : 1; // 占倒数第三位
        } _tallRichHandsome;
    }
    - (void)setTall:(BOOL)tall {
        _tallRichHandsome.tall = tall;
    }
    - (BOOL)isTall {
        return !!_tallRichHandsome.tall;
    }
    - (void)setRich:(BOOL)rich {
        _tallRichHandsome.rich = rich;
    }
    - (BOOL)isRich {
        return !!_tallRichHandsome.rich;
    }
    - (void)setHandsome:(BOOL)handsome {
        _tallRichHandsome.handsome = handsome;
    }
    - (BOOL)isHandsome {
        return !!_tallRichHandsome.handsome;
    }
    @end
    

    2,说明

    • 结构体中三个成员虽然都是char类型,但并不是各占一个字节,而是各占一位
    • 结构体的大小是所有成员大小的总和,本应该只占三位的,但结构体的最小单位是字节,所以就占一个字节
    四,共用体

    1,实例代码

    #define TallMask     (1<<0)
    #define RichMask     (1<<1)
    #define HandsomeMask (1<<2)
    
    @implementation Person
    {
        // 占一个字节
        union {
            char bits;
            // 增加可读性
            struct {
                char tall : 1;
                char rich : 1;
                char handsome : 1
            };
        } _tallRichHandsome;
    }
    - (void)setTall:(BOOL)tall {
        if (tall) {
            _tallRichHandsome.bits |= TallMask;
        } else {
            _tallRichHandsome.bits &= ~TallMask;
        }
    }
    - (BOOL)isTall {
        return !!(_tallRichHandsome.bits & TallMask);
    }
    - (void)setRich:(BOOL)rich {
        if (rich) {
            _tallRichHandsome.bits |= RichMask;
        } else {
            _tallRichHandsome.bits &= ~RichMask;
        }
    }
    - (BOOL)isRich {
        return !!(_tallRichHandsome.bits & RichMask);
    }
    - (void)setHandsome:(BOOL)handsome {
        if (handsome) {
            _tallRichHandsome.bits |= HandsomeMask;
        } else {
            _tallRichHandsome.bits &= ~HandsomeMask;
        }
    }
    - (BOOL)isHandsome {
        return !!(_tallRichHandsome.bits & HandsomeMask);
    }
    @end
    

    2,说明

    • BOOL值都存储在bits中,结构体没有实际意义,只为增加可读性
    • 共用体的大小是最大成员的大小,bits和结构体都占一个字节,所以共用体也占一个字节
    五,NS_OPTIONS
    // 每个选项占一位
    typedef NS_OPTIONS(NSUInteger, MyOptions) {
        MyOptionsNone  = 0,      // 0b00000000
        MyOptionsOne   = 1 << 0, // 0b00000001
        MyOptionstwo   = 1 << 1, // 0b00000010
        MyOptionsThree = 1 << 2  // 0b00000100
    };
    
    - (void)setOptions:(MyOptions)options {
        // 0b00000101 & 0b00000001 = 0b00000001
        if (options & MyOptionsOne) {
            NSLog(@"options包含MyOptionsOne");
        }
        // 0b00000101 & 0b00000010 = 0b00000000
        if (options & MyOptionstwo) {
            NSLog(@"options包含MyOptionstwo");
        }
        // 0b00000101 & 0b00000100 = 0b00000100
        if (options & MyOptionsThree) {
            NSLog(@"options包含MyOptionsThree");
        }
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // 0b00000001 | 0b00000100 = 0b00000101
        MyOptions options = MyOptionsOne | MyOptionsThree;
        [self setOptions:options];
    }
    
    // 打印
    options包含MyOptionsOne
    options包含MyOptionsThree
    
    六,isa_t

    源码下载地址

    1,在arm64之前,isa就是一个普通的指针,只存储class对象或meta-class对象的内存地址

    struct objc_object {
        Class isa;
    };
    

    2,从arm64开始,isa就不是一个普通的指针了,而是一个共用体,不仅存储了class对象或meta-class对象的内存地址,而且还存储了其他更多的信息

    struct objc_object {
        isa_t isa;
    };
    
    union isa_t {
        // 占八个字节
        uintptr_t bits;
        struct {
        # if __arm64_ // iOS平台
            uintptr_t nonpointer        : 1;
            uintptr_t has_assoc         : 1;
            uintptr_t has_cxx_dtor      : 1;
            uintptr_t shiftcls          : 33;
            uintptr_t magic             : 6;
            uintptr_t weakly_referenced : 1;
            uintptr_t deallocating      : 1;
            uintptr_t has_sidetable_rc  : 1;
            uintptr_t extra_rc          : 19
        # elif __x86_64__ // Mac平台
            uintptr_t nonpointer        : 1;
            uintptr_t has_assoc         : 1;
            uintptr_t has_cxx_dtor      : 1;
            uintptr_t shiftcls          : 44;
            uintptr_t magic             : 6;
            uintptr_t weakly_referenced : 1;
            uintptr_t deallocating      : 1;
            uintptr_t has_sidetable_rc  : 1;
            uintptr_t extra_rc          : 8
        #endif
        };
    };
    

    3,各位域的含义

    • nonpointer

    0表示isa是普通指针;1表示isa是共用体

    • has_assoc

    是否设置过关联对象

    • has_cxx_dtor

    是否含有C++析构函数

    • shiftcls

    存储class对象或meta-class对象的内存地址

    • magic

    对象是否完成初始化

    • weakly_referenced

    对象是否被弱指针引用过

    • deallocating

    对象是否正在销毁

    • extra_rc

    存储的值是对象的引用计数减1

    • has_sidetable_rc

    0表示引用计数存储在extra_rc中;1表示引用计数存储在SideTable中(当引用计数过大extra_rc存储不下时)

    七,ISA_MASK

    1,底层代码

    # if __arm64_
        /*
         从倒数第四位开始有33个1
         0000 0000 0000 0000 0000 0000 0000 1111
         1111 1111 1111 1111 1111 1111 1111 1000
         */
        # define ISA_MASK 0x0000000ffffffff8ULL
    # elif __x86_64__
        /*
         从倒数第四位开始有44个1
         0000 0000 0000 0000 0111 1111 1111 1111
         1111 1111 1111 1111 1111 1111 1111 1000
         */
        # define ISA_MASK 0x00007ffffffffff8ULL
    #endif
    
    inline Class objc_object::ISA() {
        // 取出class对象或meta-class对象的内存地址
        return (Class)(isa.bits & ISA_MASK);
    }
    

    2,打印验证(Mac平台)

    Class无法打印isa的地址,所以用yj_objc_class代替,它就是objc_class,只是加了个前缀而已

    NSObject *instance = [[NSObject alloc] init];
    yj_objc_class *clas = (__bridge yj_objc_class *)[NSObject class];
    Class metaClass = object_getClass([NSObject class]);
    
    ISA_MASK

    相关文章

      网友评论

        本文标题:Runtime:isa原理分析

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