isa 結(jié)構(gòu)分析

我們要進(jìn)行isa的分析首先掌握的知識(shí)
1售貌、聯(lián)合體(共用體)
1.1、使用位運(yùn)算 進(jìn)行 存取 數(shù)據(jù)
1.2啃憎、位域 簡(jiǎn)介
1.3、結(jié)構(gòu)體位域優(yōu)化代碼
1.4似炎、聯(lián)合體優(yōu)化代碼
2辛萍、clang
2.1 clang 簡(jiǎn)介
2.2 簡(jiǎn)單用法
2.3 clang 源碼 查看線索
3悯姊、isa_t聯(lián)合體

1、聯(lián)合體union

聯(lián)合體union的定義方式與結(jié)構(gòu)體一樣贩毕,但是二者有根本區(qū)別悯许。

什么是聯(lián)合體(union)呢?聯(lián)合體是一種特殊的類辉阶,也是一種構(gòu)造類型的數(shù)據(jù)結(jié)構(gòu)先壕。完全就是共用一個(gè)內(nèi)存首地址,并且各種變量名都可以同時(shí)使用睛藻,操作也是共同生效启上。所以也叫共用體。并且聯(lián)合體(union)中是各變量是“互斥”的店印,但是內(nèi)存使用更為精細(xì)靈活,也節(jié)省了內(nèi)存空間倒慧。

在結(jié)構(gòu)體??中各成員有各自的內(nèi)存空間按摘,一個(gè)結(jié)構(gòu)變量總長(zhǎng)度是各成員長(zhǎng)度之和。而在“聯(lián)合”中纫谅,各成員共享一段內(nèi)存空間炫贤,一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度

1.1付秕、使用位運(yùn)算 進(jìn)行 存取 數(shù)據(jù)

廢話不多 我們定義一個(gè)LHCar類 這個(gè)類 有up down left right 四個(gè)代表方向的BOOL類型的屬性

@interface LHCar : NSObject

@property (nonatomic, assign) BOOL up;
@property (nonatomic, assign) BOOL down;
@property (nonatomic, assign) BOOL left;
@property (nonatomic, assign) BOOL right;
 
@end

進(jìn)行打印

2020-09-09 23:41:04.086760+0800 isa結(jié)構(gòu)分析[4982:341540] 16

輸出為16字節(jié) 其中包括 isa 和4個(gè)BOOL類型的屬性 共 8+1+1+1+1 = 12 內(nèi)存對(duì)齊 為 16 字節(jié)
我們知道 BOOL值 只有兩種情況 01 , 一個(gè)字節(jié)8個(gè)二進(jìn)制位 兰珍,并且二進(jìn)制 只有 01 想到這里 那么我們完全可以使用一個(gè)二進(jìn)制位來表示 一個(gè)BOOL值 。也就是這四個(gè)BOOL屬性 我們可以用4個(gè)二進(jìn)制位來表示如下圖 询吴,大大節(jié)省了內(nèi)存空間

截屏2020-09-10上午9.20.36.png

按照我們的臆想來實(shí)現(xiàn)代碼掠河,首先分別聲明 up down left right 掩碼 mask ,來方便我們位運(yùn)算取值賦值

#define LHDirectionUpMask    0b00001000
#define LHDirectionDownMask  0b00000100
#define LHDirectionLeftMask  0b00000010
#define LHDirectionRightMask 0b00000001

定義 char 類型 的成員變量

@interface LHCar(){
     
    char _upDownLeftRight;
}
@end

初始化

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

自定義setter


-(void)setUp:(BOOL)up
{
    if (up) {
        /// 如果需要將值置為1猛计,將源碼和掩碼進(jìn)行按位或運(yùn)算
        _upDownLeftRight |= LHDirectionUpMask;
    }else{
        /// 如果需要將值置為0 // 將源碼和按位取反后的掩碼進(jìn)行按位與運(yùn)算
        _upDownLeftRight &= ~LHDirectionUpMask;
    }
}

-(void)setDown:(BOOL)down
{
    if (down) {
        _upDownLeftRight |= LHDirectionDownMask;
    }else{
        _upDownLeftRight &= ~ LHDirectionDownMask;
    }
}

- (void)setLeft:(BOOL)left
{
    if (left) {
        _upDownLeftRight |= LHDirectionLeftMask;
    } else {
        _upDownLeftRight &= ~LHDirectionLeftMask;
    }
}

- (void)setRight:(BOOL)right
{
    if (right) {
        _upDownLeftRight |= LHDirectionRightMask;
    } else {
        _upDownLeftRight &= ~LHDirectionRightMask;
    }
}

getter

-(BOOL)isUp
{
    return !!(_upDownLeftRight & LHDirectionUpMask);
}
-(BOOL)isDown
{
    return !!(_upDownLeftRight & LHDirectionDownMask);
}

-(BOOL)isLeft
{
    return !!(_upDownLeftRight & LHDirectionLeftMask);
 
}
-(BOOL)isRight
{
    return !!(_upDownLeftRight & LHDirectionRightMask);

}

按照?qǐng)D上示意 及我們的想法 這時(shí)候調(diào)用getter方法打印 初始化值

 LHCar * car = [[LHCar alloc]init];
 NSLog(@"up:%d down:%d left:%d right:%d",car.isUp,car.isDown,car.isLeft,car.isRight);
截屏2020-09-10上午9.47.22.png

我們屏蔽之前定義的屬性 調(diào)用自定義的setter方法進(jìn)行賦值

      LHCar * car = [[LHCar alloc]init];
        [car setUp:YES];
        [car setDown:NO];
        [car setLeft:YES];
        [car setRight:NO];
        NSLog(@"up:%d down:%d left:%d right:%d",car.isUp,car.isDown,car.isLeft,car.isRight);
截屏2020-09-10上午9.44.56.png

發(fā)現(xiàn)我們用一個(gè)字節(jié)的里的4個(gè)二進(jìn)制位 就完成了 之前的 占有4個(gè)字節(jié)的 4個(gè)屬性的讀寫

1.2唠摹、位域 簡(jiǎn)介

有些信息在存儲(chǔ)時(shí),并不需要占用一個(gè)完整的字節(jié)奉瘤,而只需占幾個(gè)或一個(gè)二進(jìn)制位勾拉。例如在存放一個(gè)開關(guān)量時(shí),只有01兩種狀態(tài)盗温,用1位 二進(jìn)制位即可藕赞。為了節(jié)省存儲(chǔ)空間并使處理簡(jiǎn)便,C語言又提供了一種數(shù)據(jù)結(jié)構(gòu)卖局,稱為"位域"或"位段"

所謂"位域"是把一個(gè)字節(jié)中的二進(jìn)位劃分為幾個(gè)不同的區(qū)域斧蜕,并說明每個(gè)區(qū)域的位數(shù)。每個(gè)域有一個(gè)域名吼驶,允許在程序中按域名進(jìn)行操作惩激。這樣就可以把幾個(gè)不同的對(duì)象用一個(gè)字節(jié)的二進(jìn)制位域來表示店煞。

位域的定義和位域變量的說明
struct 位域結(jié)構(gòu)名

{

位域列表

};

例如:

struct bs

{

int a:8;

int b:2;

int c:6;

}data;


說明 data 為 bs 變量,共占兩個(gè)字節(jié)风钻,其中位域a占8位顷蟀,位域b占2位,位域 c 占6位骡技。

位域定義說明

1鸣个、 一個(gè)位域必須存儲(chǔ)在同一個(gè)字節(jié)中,不能跨兩個(gè)字節(jié)布朦。如一個(gè)字節(jié)所识谟空間不夠存放另一位域時(shí),應(yīng)從下一單元起存放該位域
2是趴、由于位域不允許跨兩個(gè)字節(jié)涛舍,因此位域的長(zhǎng)度不能大于一個(gè)字節(jié)的長(zhǎng)度,也就是說不能超過8位二進(jìn)位唆途。(如果最大長(zhǎng)度大于計(jì)算機(jī)的整數(shù)字長(zhǎng)富雅,一些編譯器可能會(huì)允許域的內(nèi)存重疊,另外一些編譯器可能會(huì)把大于一個(gè)域的部分存儲(chǔ)在下一個(gè)字中肛搬。)
3没佑、位域可以是無名位域,這時(shí)它只用來作填充或調(diào)整位置温赔。無名的位域是不能使用的

1.3蛤奢、結(jié)構(gòu)體位域優(yōu)化代碼

我們了解了位域的基本信息那么我們可以用結(jié)構(gòu)體位域來優(yōu)化代碼


#import "LHCar.h"

//#define LHDirectionUpMask    0b00001000
//#define LHDirectionDownMask  0b00000100
//#define LHDirectionLeftMask  0b00000010
//#define LHDirectionRightMask 0b00000001

@interface LHCar(){
//
//    char _upDownLeftRight;
    
    struct{
        char up   : 1;
        char down : 1;
        char left : 1;
        char right: 1;
    }_upDownLeftRight;
    
    
    
}
@end

@implementation LHCar
- (instancetype)init
{
    self = [super init];
    if (self) {
//        _upDownLeftRight = 0b00000001;
        
        
        
    }
    return self;
}

-(void)setUp:(BOOL)up
{
//    if (up) {
//        /// 如果需要將值置為1,將源碼和掩碼進(jìn)行按位或運(yùn)算
//        _upDownLeftRight |= LHDirectionUpMask;
//    }else{
//        /// 如果需要將值置為0 // 將源碼和按位取反后的掩碼進(jìn)行按位與運(yùn)算
//        _upDownLeftRight &= ~LHDirectionUpMask;
//    }
    
    _upDownLeftRight.up = up;
    
}

-(void)setDown:(BOOL)down
{
//    if (down) {
//        _upDownLeftRight |= LHDirectionDownMask;
//    }else{
//        _upDownLeftRight &= ~ LHDirectionDownMask;
//    }
      _upDownLeftRight.down = down;
}

- (void)setLeft:(BOOL)left
{
//    if (left) {
//        _upDownLeftRight |= LHDirectionLeftMask;
//    } else {
//        _upDownLeftRight &= ~LHDirectionLeftMask;
//    }
    _upDownLeftRight.left = left;
    
}

- (void)setRight:(BOOL)right
{
//    if (right) {
//        _upDownLeftRight |= LHDirectionRightMask;
//    } else {
//        _upDownLeftRight &= ~LHDirectionRightMask;
//    }
    _upDownLeftRight.right = right;
}
 
-(BOOL)isUp
{
//    return !!(_upDownLeftRight & LHDirectionUpMask);
    
    return !!_upDownLeftRight.up;
}
-(BOOL)isDown
{
//    return !!(_upDownLeftRight & LHDirectionDownMask);
    return !!_upDownLeftRight.down;
}

-(BOOL)isLeft
{
//    return !!(_upDownLeftRight & LHDirectionLeftMask);
    return !!_upDownLeftRight.left;
 
}
-(BOOL)isRight
{
//    return !!(_upDownLeftRight & LHDirectionRightMask);
    return !!_upDownLeftRight.right;

}
@end

這樣是可以正常存取 但是去掉了 掩碼mask 和初始化代碼 導(dǎo)致可讀性非常差 這時(shí)聯(lián)合體出來了

1.4陶贼、聯(lián)合體優(yōu)化代碼

#import "LHCar.h"

#define LHDirectionUpMask    0b00001000
#define LHDirectionDownMask  0b00000100
#define LHDirectionLeftMask  0b00000010
#define LHDirectionRightMask 0b00000001

@interface LHCar(){
    union{
        char bits;
        struct{
            char up   : 1;
            char down : 1;
            char left : 1;
            char right: 1;
        };
        
    }_upDownLeftRight;
 
    
    
}
@end

@implementation LHCar
- (instancetype)init
{
    self = [super init];
    if (self) {
        _upDownLeftRight.bits = 0b00000001;
        
        
        
    }
    return self;
}

-(void)setUp:(BOOL)up
{
    if (up) {
 
        _upDownLeftRight.bits |= LHDirectionUpMask;
    }else{
        _upDownLeftRight.bits &= ~LHDirectionUpMask;
    }
 
    
}

-(void)setDown:(BOOL)down
{
    if (down) {
        _upDownLeftRight.bits |= LHDirectionDownMask;
    }else{
        _upDownLeftRight.bits &= ~ LHDirectionDownMask;
    }
     
}

- (void)setLeft:(BOOL)left
{
    if (left) {
        _upDownLeftRight.bits |= LHDirectionLeftMask;
    } else {
        _upDownLeftRight.bits &= ~LHDirectionLeftMask;
    }
    
    
}

- (void)setRight:(BOOL)right
{
    if (right) {
        _upDownLeftRight.bits |= LHDirectionRightMask;
    } else {
        _upDownLeftRight.bits &= ~LHDirectionRightMask;
    }
    
}
 
-(BOOL)isUp
{
    return !!(_upDownLeftRight.bits & LHDirectionUpMask);
    
  
}
-(BOOL)isDown
{
    return !!(_upDownLeftRight.bits & LHDirectionDownMask);
 }

-(BOOL)isLeft
{
     return !!(_upDownLeftRight.bits & LHDirectionLeftMask);
    
 
}
-(BOOL)isRight
{
    return !!(_upDownLeftRight.bits & LHDirectionRightMask);
 
}
@end

測(cè)試發(fā)現(xiàn)依舊可以 完成 存取

其中 _upDownLeftRight 聯(lián)合體只 占用了一個(gè)字節(jié) 因?yàn)榻Y(jié)構(gòu)體中
up啤贩、downleft骇窍、right瓜晤、都只占用一位二進(jìn)制空間,這就是 4 個(gè)二進(jìn)制空間 而 char 類型 bits 也只占用了一個(gè)字節(jié) 他們都在聯(lián)合體中 因此 共用一個(gè)字節(jié)的內(nèi)存

總結(jié): 通過掩碼進(jìn)行位運(yùn)算來增加 效率 通過聯(lián)合體結(jié)構(gòu) 可以 節(jié)省內(nèi)存空間

2腹纳、clang用法

2.1痢掠、簡(jiǎn)介

Clang是一個(gè)C語言、C++嘲恍、Objective-C足画、C++語言的輕量級(jí)編譯器。源代碼發(fā)布于BSD協(xié)議下佃牛。也是Xcode 第一的編譯器

2.2 簡(jiǎn)單使用

clang -rewrite-objc main.m -o main.cpp 把目標(biāo)文件編譯成c++文件 UIKit報(bào)錯(cuò)問題

clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m

xcode安裝的時(shí)候順帶安裝了xcrun命令淹辞,xcrun命令在clang的基礎(chǔ)上進(jìn)行了 一些封裝,要更好用一些

xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (模擬器)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp (手機(jī))

clang就說這么多 具體深究請(qǐng)自行查閱 注意:查看模擬器版本 以及 源文件

準(zhǔn)備一段代碼 clang 其本質(zhì)

#import <Foundation/Foundation.h>
 
@interface LHPerson : NSObject
{
    NSString * nickName;
}

@property (nonatomic, copy) NSString *name;
 
@end

@implementation LHPerson
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
 
    }
    return 0;
}

clang過后 我們根據(jù)LHPerson為深入線索俘侠,進(jìn)行搜索

struct LHPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *__strong nickName;
    NSString *__strong _name;
};


// @property (nonatomic, copy) NSString *name;



/* @end */


// @implementation LHPerson

static NSString * _I_LHPerson_name(LHPerson * self, SEL _cmd) { return (*(NSString *__strong *)((char *)self + OBJC_IVAR_$_LHPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_LHPerson_setName_(LHPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LHPerson, _name), (id)name, 0, 1); }
// @end

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

    }
    return 0;
}

NSObject_IMPL又是什么象缀?

struct NSObject_IMPL {
    __unsafe_unretained Class isa;
};

通過上面總結(jié)
1蔬将、一個(gè)類的聲明或創(chuàng)建 底層實(shí)現(xiàn) 就是 一個(gè)結(jié)構(gòu)體
2、Class其實(shí)就是一個(gè)指針 指向了 objc_class類型的結(jié)構(gòu)體
3央星、LHPerson_IMPL 結(jié)構(gòu)體中有3個(gè)成員變量 isanickName _name
4霞怀、屬性自動(dòng)生成 getter setter 方法 并且?guī)臀覀冝D(zhuǎn)成 _name
5、nickName并沒有生成getter setter
6莉给、selfSEL _cmd 為默認(rèn)參數(shù)

3毙石、isa_t聯(lián)合體

union isa_t


union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

由上面的介紹聯(lián)合體概念可以知道,cls和bits之間是互斥的颓遏,即有cls就沒有bits,有bits就沒有cls徐矩。

initInstanceIsa

我們知道alloc的流程 最重要的 是 三部曲

1、 size = cls->instanceSize(extraBytes); ///計(jì)算 需要多少內(nèi)存空間
2叁幢、 obj = (id)calloc(1, size); // alloc 開辟內(nèi)存的地方
3滤灯、 obj->initInstanceIsa(cls, hasCxxDtor);///關(guān)聯(lián)對(duì)應(yīng)的類

objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    ASSERT(!cls->instancesRequireRawIsa());
    ASSERT(hasCxxDtor == cls->hasCxxDtor());

    initIsa(cls, true, hasCxxDtor);
}

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());

        isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
}

這就很好地解釋了為什么上面的源碼在初始化isa的時(shí)候會(huì)用nonpointer來區(qū)分開。所以isa的大小占8個(gè)字節(jié)曼玩,64位力喷。其中這64位中分別存儲(chǔ)了什么呢?通過ISA_BITFIELD位域

ISA_BITFIELD 位域
# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      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 deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

# else
#   error unknown architecture for packed isa
# endif

這兩種是分別在arm64和x86系統(tǒng)架構(gòu)下的演训,但是都是64位的,本文的說明是在x86下介紹的贝咙。

nonpointer: 表示是否對(duì)isa指針開啟指針優(yōu)化 0:純isa指針样悟,1:不止是類對(duì)象地址,isa中包含了類信息庭猩,對(duì)象的引用計(jì)數(shù)等
has_assoc:關(guān)聯(lián)對(duì)象標(biāo)志位窟她,0沒有,1存在
has_cxx_dtor:該對(duì)象是否有 C++ 或者 Objc 的析構(gòu)器,如果有析構(gòu)函數(shù),則需要做析構(gòu)邏輯, 如果沒有,則可以更快的釋放對(duì)象

shiftcls: 存儲(chǔ)類指針的值蔼水。開啟指針優(yōu)化的情況下震糖,在 arm64 架構(gòu)中有 33 位用來存儲(chǔ)類指針。x86_64 下 44 位
magic:用于調(diào)試器判斷當(dāng)前對(duì)象是真的對(duì)象還是沒有初始化的空間
weakly_referenced:志對(duì)象是否被指向或者曾經(jīng)指向一個(gè) ARC 的弱變量趴腋,
沒有弱引用的對(duì)象可以更快釋放
deallocating:標(biāo)志對(duì)象是否正在釋放內(nèi)存
has_sidetable_rc:當(dāng)對(duì)象引用技術(shù)大于 10 時(shí)吊说,則需要借用該變量存儲(chǔ)進(jìn)位
extra_rc:當(dāng)表示該對(duì)象的引用計(jì)數(shù)值,實(shí)際上是引用計(jì)數(shù)值減 1优炬, 例如颁井,如果對(duì)象的引用計(jì)數(shù)為 10,那么 extra_rc 為 9蠢护。如果引用計(jì)數(shù)大于 10雅宾, 則需要使用到下面的 has_sidetable_rc。

lldb指令驗(yàn)證

截屏2020-09-10下午2.46.41.png

x/4gx person : 打印出地址
p/x LHPerson.class : 打印類的內(nèi)存地址

通過源碼 搜索 object_getClass

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
objc_object::getIsa() 
{
    if (fastpath(!isTaggedPointer())) return ISA();

    extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
    uintptr_t slot, ptr = (uintptr_t)this;
    Class cls;

    slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
    cls = objc_tag_classes[slot];
    if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
        slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
        cls = objc_tag_ext_classes[slot];
    }
    return cls;
}
inline Class 
objc_object::ISA() 
{
    ASSERT(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

從源碼中可以知道返回的isa最終是(Class)(isa.bits & ISA_MASK)葵硕。
p/x :0x00007ffffffffff8ULL & 0x001d80010000233d

截屏2020-09-10下午3.02.08.png

最終發(fā)現(xiàn)
1和
2的內(nèi)存值是一樣的眉抬,所以isa是關(guān)聯(lián)著對(duì)象與類的贯吓。

根據(jù)上面我們對(duì)聯(lián)合體的大概了解 我們也知道 那么我們是不是可以不用面具mask 直接通過<<< >>>也可以拿到類的信息 x86下類信息在 isa 的位域 44
截屏2020-09-10下午3.49.56.png

繼續(xù)p/x 做位移運(yùn)算


截屏2020-09-10下午4.33.46.png

我的天 isa 指針中 真的包含 類的信息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蜀变,隨后出現(xiàn)的幾起案子悄谐,更是在濱河造成了極大的恐慌,老刑警劉巖昏苏,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尊沸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贤惯,警方通過查閱死者的電腦和手機(jī)洼专,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孵构,“玉大人屁商,你說我怎么就攤上這事【笔” “怎么了蜡镶?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恤筛。 經(jīng)常有香客問我官还,道長(zhǎng),這世上最難降的妖魔是什么毒坛? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任望伦,我火速辦了婚禮,結(jié)果婚禮上煎殷,老公的妹妹穿的比我還像新娘屯伞。我一直安慰自己,他們只是感情好豪直,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布劣摇。 她就那樣靜靜地躺著,像睡著了一般弓乙。 火紅的嫁衣襯著肌膚如雪末融。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天唆貌,我揣著相機(jī)與錄音滑潘,去河邊找鬼。 笑死锨咙,一個(gè)胖子當(dāng)著我的面吹牛语卤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼粹舵,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼钮孵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起眼滤,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤巴席,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后诅需,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漾唉,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年堰塌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赵刑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡场刑,死狀恐怖般此,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情牵现,我是刑警寧澤铐懊,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站瞎疼,受9級(jí)特大地震影響科乎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贼急,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一喜喂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竿裂,春花似錦、人聲如沸照弥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽这揣。三九已至悔常,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間给赞,已是汗流浹背机打。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留片迅,地道東北人残邀。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親芥挣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驱闷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355