美文网首页
isa指针(二)

isa指针(二)

作者: 小冰山口 | 来源:发表于2024-03-13 14:42 被阅读0次

    isa指针(一)
    前面的文章中, 讲到了isa指针, 不过留了个小尾巴
    instanceisa指针并不是直接指向类对象的. 而是与上了一个ISA_MASK的东西, 那这是为什么呢?

    试图解开这个谜底, 就先要搞清楚什么是位域和联合体

    位域的概念和应用, 我在这篇文章里面有提到:
    位域

    假设现在有这样一个需求

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Person : NSObject
    
    // 是否是男性
    - (void)setMale:(BOOL)male;
    - (BOOL)male;
    
    // 是否是汉族
    - (void)setHan:(BOOL)han;
    - (BOOL)han;
    
    // 是否成年
    - (void)setGrown:(BOOL)grown;
    - (BOOL)grown;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    有一个类要存储三个BOOL类型的变量, 如果直接用属性, 那就会自动生成三个BOOL类型的变量, 就是3个字节, 但我们发现, BOOL类型, 不是0, 就是1, 我根本不需要一个字节去保存, 用一位就够了, 那我三个变量共用1个字节就完全够了, 这时候就能用到联合体

    #import "Person.h"
    
    #define kMaleMask (1<<0)
    #define kHanMask (1<<1)
    #define kGrownMask (1<<2)
    
    union PersonFeatures {
        char bits;
        struct {
            char male :1;
            char han :1;
            char grown :1;
        };
    };
    
    @implementation Person  {
        union PersonFeatures personFeatures;
    }
    
    - (void)setMale:(BOOL)male {
        if (male) {
            personFeatures.bits |= kMaleMask;
        }else {
            personFeatures.bits &= ~kMaleMask;
        }
    }
    
    - (BOOL)male {
        return personFeatures.bits & kMaleMask;
    }
    
    - (void)setHan:(BOOL)han {
        if (han) {
            personFeatures.bits |= kHanMask;
        }else {
            personFeatures.bits &= ~kHanMask;
        }
    }
    
    - (BOOL)han {
        return personFeatures.bits & kHanMask;
    }
    
    - (void)setGrown:(BOOL)grown {
        if (grown) {
            personFeatures.bits |= kGrownMask;
        }else {
            personFeatures.bits &= ~kGrownMask;
        }
    }
    
    - (BOOL)grown {
        return personFeatures.bits & kGrownMask;
    }
    
    
    @end
    

    在下面这个联合体中

    union PersonFeatures {
        char bits;
        struct {
            char male :1;
            char han :1;
            char grown :1;
        };
    };
    

    其实这个结构体并没有什么用, 它只是用来增加可读性的, 当然, 你结构体的位数不能超过你在联合体中定义的那个成员变量所在内存中占用的字节数

        struct {
            char male :1;
            char han :1;
            char grown :1;
        };
    

    所以事实上, 联合体就是

    union PersonFeatures {
        char bits;
    }
    

    因为我们用的时候, 也只是用了bits, 用bits通过一些位运算, 来取出或者存上具体哪一位, 或者哪几位的值.

    image.png

    那我们看回isa指针

    image.png
    源码中, 一个struct objc_object结构体其实只有一个成员变量, 简化过来就是
    struct objc_object {
        char isa_storage[sizeof(isa_t)];
    }
    

    也就是说, struct objc_object结构体的成员变量是一个char类型的数组, 这个数组的长度是isa_t的所占内存空间的大小, 那isa_t又是个什么玩意儿呢? isa_t就是我们所说的联合体:

    image.png

    简化下来就是:

    union isa_t {
        uintptr_t bits;
        struct {
            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 unused            : 1;
            uintptr_t has_sidetable_rc  : 1;
            uintptr_t extra_rc          : 19
        };
    }
    

    看起来是不是跟我们之前自定义的那种共用体很像了?
    所以苹果就是利用这种方式, 去与&上一个特定的值, 那取到真正的isa指针, 或者其他的值.
    比如:

    图片来源小码哥 图片来源小码哥

    相关文章

      网友评论

          本文标题:isa指针(二)

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