iOS相关技术原理Runtime & Runloop

Runtime:isa原理分析

2020-02-05  本文已影响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,实例代码

@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,说明

四,共用体

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,说明

五,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,各位域的含义

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

是否设置过关联对象

是否含有C++析构函数

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

对象是否完成初始化

对象是否被弱指针引用过

对象是否正在销毁

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

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
上一篇下一篇

猜你喜欢

热点阅读