专栏首页老沙课堂isa详解(一)isa结构

isa详解(一)isa结构

从iOS 源码中我们可以找到以下结构体 。从这里我们开始看一下isa的构成

struct objc_object {
private:
    isa_t isa;
};
复制代码
union isa_t {
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD) // 我们看一下这个宏
    struct {
        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)
复制代码

所以在arm64环境下isa如下所示

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 deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
  }
};
复制代码

所以为了探究isa 我们先研究下union

1. union

为什么要用union以及位运算呢。因为在计算机中为二进制。位运算是最快速的计算方式 union C++ 中的共用体。顾名思义 就是在union 中 公用一个内存地址 。

结构体 位域 : 1 只占一位

struct {
char a : 1; //1位
char b : 1; //1位
char c : 1; //1位
} temp; //3位 1个字节

struct {
char a; //1个字节
char b; //1个字节
char c; //1个字节
} temp; // 3个字节

union {
  char bits; // 一个字节
  // struct 只是可读性,有和没有都一样
  struct {
    char a : 1; //1位
    char b : 1; //1位
    char c : 1; //1位
  } temp;
} unionInstance

复制代码

union的内存结构如下图所示,两个指针指针同时管理一个内存地址。因为我们不操作struct中的 所以struct只是增强可读性。表示每个字节代表的含义。

2. 如果我们想访问union 中a,b,c的值如何设置 如何访问呢

#import "Person.h"
#define aMask (1<<0)
#define bMask (1<<1)
#define cMask (1<<2)
@interface Person()
{
    union {
        char bits;
        struct {
            int a : 1;
            int b : 1;
            int c : 1;
        } temp;
    } _property;
}
@end
@implementation Person

- (instancetype)init
{
    self = [super init];
    if (self) {
        self->_property.bits = 0b00000000;
    }
    return self;
}

- (void)setAvar:(BOOL) a {
    if (a == YES) {
        self->_property.bits |= aMask;
    }else {
        self->_property.bits =  (self->_property.bits & ~aMask);
    }
    
}
- (BOOL)a {
    return !!(self->_property.bits & aMask);
}

- (void)setBvar:(BOOL) b {
    if (b == YES) {
        self->_property.bits |= bMask;
    }else {
        self->_property.bits =  (self->_property.bits & ~bMask);
    }
    
}
- (BOOL)b {
    return !!(self->_property.bits & bMask);
}

- (void)setCvar:(BOOL) c {
    if (c == YES) {
        self->_property.bits |= cMask;
    }else {
        self->_property.bits =  (self->_property.bits & ~cMask);
    }
    
}
- (BOOL)c {
    return !!(self->_property.bits & cMask);
}
@end
复制代码
    Person *person = [Person new];
    [person setAvar:NO];
    [person setBvar:YES];
    [person setCvar:NO];
    NSLog(@"a = %d, b = %d, c = %d",person.a,person.b,person.c);
复制代码

输出结果为

    runtime-isa详解01[8059:19727104] a = 0, b = 1, c = 0
复制代码

isa指向

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 或者是meta-class

但是源码上为什么要 & ISA_MASK 呢。

从上面的有关union以及位运算 我们可知道 通过 &运算符 可以找到对应的union中所指向位数包含的信息

#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL

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 deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
  }
};
复制代码

从上面代码我们可以知道 ISA_MASK的值为0x0000000ffffffff8ULL 所对应的取值就是isa bits 中的shiftcls所在的字节 所以 这里面才是指向class 或者meta-class的地址

  • 所以我们有一下结论

arm64之前直接指向class 或者是meta-class arm64之后 isa & ISA_MASK 为class 或者meta-class 地址。isa为 union 结构,用位域来存储更多信息 union 共用体 公用一个内存

本文分享自微信公众号 - 老沙课堂(gh_f73a6b772d4f),作者:rui4u

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RunLoop详解

    线程刚创建的时候没有Ru nLoop对象,RunLoop会在第一次获取它的时候创建

    老沙
  • 消息转发及super

    **消息转发的时候。由于oc的底层原理是消息机制,所以可以添加c语言函数等 **

    老沙
  • NSProxy 设计消息转发

    继承于NSProxy的类 找实现方法的时候 只会找当前类是否实现 而不找super,如果没找到直接进入消息动态解析,以及消息转发机制。比继承NSObject的类...

    老沙
  • C# 判断文件编码

    我们的项目中会包含有很多文件,但是可能我们没有注意到的,我们的文件的编码不一定是utf-8,所以可能在别人电脑运行时出现乱码。最近在做一个项目,这个项目可以把我...

    林德熙
  • Android项目解耦--路由框架ARouter源码解析

    上一篇文章Android项目解耦--路由框架ARouter的使用讲述了ARouter在项目中的使用,这边文章主要对ARouter的源码进行学习和分析。

    静默加载
  • 聊一下简易版的“Spring Boot”写的咋样了

    昨天早上,6 点多一点就起来写代码了,前天晚上和朋友一起吃晚饭回来之后也搞到很晚,有时候想尽快把某些东西写完的时候确实是会这样。

    Guide哥
  • ReentrantLock中的unlock流程

    在调用到ReentrantLock的unlock方法的时候,无论公平锁与非公平锁都会调用到sync.release(1)方法。

    None_Ling
  • 解密日志文件工具类

    WindWant
  • poj 1068 Parencodings(模拟)

    http://poj.org/problem?id=1068 题意:输入一组数表示左边有几个括号,输出一组数表述该右括号里搭配好了几个括号 #include<s...

    用户1624346
  • Spring Boot 概述

    Spring Boot可以以jar包的形式独立运行,运行一个Spring Boot项目只需要通过java -jar xx.jar来运行 。

    cherishspring

扫码关注云+社区

领取腾讯云代金券