美文网首页
iOS runtime 部分一

iOS runtime 部分一

作者: 飞不越疯人院 | 来源:发表于2020-07-13 22:28 被阅读0次

    主要讲解 isa 指针/方法的底层结构;

    文中使用的 objc4源码是objc-781版本;

    runtime 部分一
    runtime 部分二
    runtime 部分三


    1. 首先记录一些基础的知识点

    1.1 一个16进制位等于四个二进制的位;
    例如

    0000(十进制)=0000(二进制)=0(十六进制);
    0001(十进制)=0001(二进制)=1(十六进制); 
    0002(十进制)=0010(二进制)=2(十六进制); 
    0003(十进制)=0011(二进制)=3(十六进制); 
    0004(十进制)=0100(二进制)=4(十六进制); 
    0005(十进制)=0101(二进制)=5(十六进制); 
    0006(十进制)=0110(二进制)=6(十六进制); 
    0007(十进制)=0111(二进制)=7(十六进制); 
    0008(十进制)=1000(二进制)=8(十六进制); 
    0009(十进制)=1001(二进制)=9(十六进制); 
    0010(十进制)=1010(二进制)=A(十六进制); 
    0011(十进制)=1011(二进制)=B(十六进制); 
    0012(十进制)=1100(二进制)=C(十六进制); 
    0013(十进制)=1101(二进制)=D(十六进制); 
    0014(十进制)=1110(二进制)=E(十六进制); 
    0015(十进制)=1111(二进制)=F(十六进制);
    

    1.2 一些常见的二进制位操作
    位运算 &

       0001 1000
    &  0000 1001
    --------------
       0000 1000
    

    位运算 |

        0001 1000
    |   0000 1001
    --------------
        0001 1001
    

    位运算 ~

         ~0001 1000
     --------------
          1110 0111
    
    

    位的左右移动

     0x0000 0001  = 1;
     
     0x0000 0001<<0 =   0x0000 0001
     0x0000 0001<<1 =   0x0000 0010
     0x0000 0001<<2 =   0x0000 0100
      
     1<<0 = 0x0000 0001
     1<<1 = 0x0000 0010
     1<<2 = 0x0000 0100
    

    取出一个二进制地址中的某一段如何操作?
    例如取出0x1000 1000 1001 1000 中间的红色那8位;
    0x1000 1000 1001 1000
    & 0x0000 1111 1111 0000 = 0x0000 1000 0001 0000 = 0x1000 0001 0000

    2. 通过共用体只用一个字节存储若干个 BOOL 值;

    共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
    通过上述的基本知识和位域的简单知识, 可以设计如下代码;

    ///.h 的接口定义
    NS_ASSUME_NONNULL_BEGIN
    ///通过共用体和位域的操作实现一个字节存放几个BOOL类型的变量
    @interface Person : NSObject
    - (void)setBig:(BOOL)big;
    - (void)setMiddle:(BOOL)middle;
    - (void)setSmall:(BOOL)small;
    
    - (BOOL)big;
    - (BOOL)middle;
    - (BOOL)small;
    @end
    NS_ASSUME_NONNULL_END
    
    ///.m 的实现
    #import "Person.h"
    ///占用一个字节的共用体
    union {
        char bits;
        ///下面结构是为了方便阅读, 并没有实际的意义
        struct {
            ///位域操作, big 只占用一位
            char big : 1;
            ///位域操作, middle 只占用一位
            char middle : 1;
            ///位域操作, small 只占用一位
            char small : 1;
        };
    }AllBool;
    
    ///通过位的左移定义掩码
    #define  BigMask    (1<<0)
    #define  MiddleMask (1<<1)
    #define  SmallMask  (1<<2)
    
    @implementation Person
    - (void)setBig:(BOOL)big {
        if (big) {
            AllBool.bits |= BigMask;
        }else {
            AllBool.bits &= ~BigMask;
        }
    }
    - (void)setMiddle:(BOOL)middle {
        if (middle) {
            AllBool.bits |= MiddleMask;
        }else {
            AllBool.bits &= ~MiddleMask;
        }
    }
    - (void)setSmall:(BOOL)small {
        if (small) {
            AllBool.bits |= SmallMask;
        }else {
            AllBool.bits &= ~SmallMask;
        }
    }
    
    - (BOOL)big {
       return !!(AllBool.big & BigMask);
    }
    - (BOOL)middle {
        return !!(AllBool.middle & MiddleMask);
    }
    - (BOOL)small {
         return !!(AllBool.small & SmallMask);
    }
    @end
    

    3. isa 指针的结构

    通过 objc4-781源码可以得到isa的结构如下;

    ///底层是一个共用体
    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
        Class cls;
        uintptr_t bits;
    #if defined(ISA_BITFIELD)
        struct {
            ///isa 的位域信息
            ISA_BITFIELD;  // defined in isa.h
        };
    #endif
    };
    ===>
    ///arm64构架
    # 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)
    /// __x86_64__构架
    # 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
    
    真机64位架构简化上述结构为:
    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
        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 deallocating      : 1;                                      
          uintptr_t has_sidetable_rc  : 1;                                     
          uintptr_t extra_rc          : 19
      }
    };
    
    

    nonpointer : 0: 代表普通指针, 存储着Class, Mete-Class对象的内存地址; 1: 代表优化过, 使用位域存储更多信息;
    has_assoc : 是否设置过关联对象(注意只要设置过即使移出了, 也算是关联过), 如果没有关联对象, 释放时会更快;
    has_cxx_dtor : 是否有C++的析构函数; 如果没有则释放时更快;
    shiftcls : 存放着Class或者Meta-Class的地址(通过将isa的地址&ISA_MASK即可得到);
    magic: 用于分别在调试时对象是否已经完成初始化;
    weakly_referenced: 标记是否弱引用指向过, 如果没有则释放时更快;
    deallocating: 标记对象是否正在释放;
    has_sidetable_rc : 用来标记引用计数是否过大不能存放在extra_rc, 如果是1, 引用计数存放在类的的一个属性SideTable中;
    extra_rc : 存放引用计数(是减一后的值);

    从64位构架开始 isa 的地址并不是直接是类对象或者元类对象而是需要& ISA_MASK才能得到其地址, 在arm64构架下 ISA_MASK = 0x0000000ffffffff8ULL ;而0x0000000ffffffff8的二进制为如下

    ISA_MASK
    isa&ISAac_MASK
    另外我们可以推断出OC中的任何 类对象元类对象的地址, 最后三个位一定是000; 16进制展示是就是末位一定是0或者8;


    参考文章和下载链接
    测试代码
    C 共用体
    共用体详解
    C 语言结构体位域
    位域的操作
    二进制的位操作
    Apple 一些源码的下载地址

    相关文章

      网友评论

          本文标题:iOS runtime 部分一

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