OC中isa指針詳解 (union 聯(lián)合體)

為什么要使用union聯(lián)合體?

比如定義一個(gè)bool值變量需要8個(gè)字節(jié),其實(shí)僅僅使用這8個(gè)字節(jié)中的一個(gè)位就可以表達(dá)的情況了,使用union就是充分利用每個(gè)字節(jié)的每一個(gè)位,節(jié)約空間。

本文主要介紹以下部分:
一. 自定義位運(yùn)算
二. 自定義位域運(yùn)算
三. 自定義聯(lián)合體
四. isa解析

一. 自定義位運(yùn)算

先看示例:

@interface Person : NSObject

- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;

- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;

@end


#import "Person.h"

#define TallMask (1<<0)
#define RichMask (1<<1)
#define HandsomeMask (1<<2)

@interface Person()
{
    char _tallRichHansome;
}
@end

@implementation Person

- (instancetype)init
{
    if (self = [super init]) {
        _tallRichHansome = 0b00000000;
    }
    return self;
}

- (void)setTall:(BOOL)tall
{
    if (tall) {
        _tallRichHansome |= TallMask;
    } else {
        _tallRichHansome &= ~TallMask;
    }
}

- (BOOL)isTall
{
    return !!(_tallRichHansome & TallMask);
}

- (void)setRich:(BOOL)rich
{
    if (rich) {
        _tallRichHansome |= RichMask;
    } else {
        _tallRichHansome &= ~RichMask;
    }
}

- (BOOL)isRich
{
    return !!(_tallRichHansome & RichMask);
}

- (void)setHandsome:(BOOL)handsome
{
    if (handsome) {
        _tallRichHansome |= HandsomeMask;
    } else {
        _tallRichHansome &= ~HandsomeMask;
    }
}

- (BOOL)isHandsome
{
    return !!(_tallRichHansome & HandsomeMask);
}

@end

  1. 上邊get方法使用!!取反兩次是因?yàn)楂@取到的值可能是2、4、8,第一次取反變成0,再次取反變成1

main函數(shù)調(diào)用

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        person.rich = YES;
        person.tall = NO;
        person.handsome = NO;
        
        NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
    }
    return 0;
}

結(jié)果為:

tall:0 rich:1 hansome:0

二. 自定義位域運(yùn)算

Person.m修改如下:

#import "Person.h"
@interface Person()
{
    struct {
        char tall : 1;
        char rich : 1;
        char handsome : 1;
    } _tallRichHandsome;
}
@end

@implementation Person

- (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
  1. 上邊get方法使用!!取反兩次是因?yàn)樵O(shè)置值為YES的時(shí)候二進(jìn)制是這樣的0b1,系統(tǒng)會(huì)自動(dòng)把這個(gè)數(shù)據(jù)變成0b11111111結(jié)果為-1,因?yàn)樵摂?shù)據(jù)不為0,所以取反就會(huì)變成0,再次取反就會(huì)變成1
    或者修改如下:
 struct {
        unsigned char tall : 1;
        unsigned char rich : 1;
        unsigned char handsome : 1;
    } _tallRichHandsome;

即添加unsigned修飾符也可解決取值為-1的問(wèn)題。

  1. tall 、rich 、 handsome 會(huì)從右至左各占一位。

三. 自定義聯(lián)合體

Person.m修改如下:

#import "Person.h"

#define TallMask (1<<0)
#define RichMask (1<<1)
#define HandsomeMask (1<<2)
#define ThinMask (1<<3)

@interface Person()
{
    union {
        int bits;
        
        struct {
            char tall : 1;
            char rich : 1;
            char handsome : 1;
            char thin : 1;
        };
    } _tallRichHandsome;
}
@end

@implementation Person

- (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);
}



- (void)setThin:(BOOL)thin
{
    if (thin) {
        _tallRichHandsome.bits |= ThinMask;
    } else {
        _tallRichHandsome.bits &= ~ThinMask;
    }
}

- (BOOL)isThin
{
    return !!(_tallRichHandsome.bits & ThinMask);
}

@end

以下代碼完全是增強(qiáng)可讀性,刪除掉完全不會(huì)有任何影響。

 struct {
            char tall : 1;
            char rich : 1;
            char handsome : 1;
            char thin : 1;
        };

通過(guò)上邊代碼的學(xué)習(xí),就可以讀懂OC底層isa指針的具體含義了。

四. isa解析

在arm64架構(gòu)之前,isa就是一個(gè)普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址
從arm64架構(gòu)開(kāi)始,對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)共用體(union)結(jié)構(gòu),還使用位域來(lái)存儲(chǔ)更多的信息

union isa_t {
    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t unused            : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19
    };
};

isa內(nèi)部的位含義

  1. nonpointer
    0,代表普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址
    1,代表優(yōu)化過(guò),使用位域存儲(chǔ)更多的信息

  2. has_assoc
    是否有設(shè)置過(guò)關(guān)聯(lián)對(duì)象,如果沒(méi)有,釋放時(shí)會(huì)更快

  3. has_cxx_dtor
    是否有C++的析構(gòu)函數(shù)(.cxx_destruct),如果沒(méi)有,釋放時(shí)會(huì)更快

  4. shiftcls
    存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址信息

  5. magic
    用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化

  6. weakly_referenced
    是否有被弱引用指向過(guò),如果沒(méi)有,釋放時(shí)會(huì)更快
    deallocating
    對(duì)象是否正在釋放

  7. extra_rc
    里面存儲(chǔ)的值是引用計(jì)數(shù)器減1

  8. has_sidetable_rc
    引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中
    如果為1,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類(lèi)的屬性中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容