对象本质 & isa解析

2021-08-11  本文已影响0人  囤囤fc

之前我们分析了alloc流程内存对齐算法, 今天我们来研究对象的本质,并对isa进行详细解析。

对象的本质探究方法 - Clang

Clang是一个由苹果主导编写,基于LVVM的C/C++/OC编译器,通过Clang的rewrite命令可以将OC代码还原为源码
新建一个工程,在main函数中创建一个类,随意添加个属性:


image.png

打开终端,cd到文件所在目录,执行clang -rewrite-objc main.m -o main.cpp

#ifndef _REWRITER_typedef_FCPerson
#define _REWRITER_typedef_FCPerson
typedef struct objc_object FCPerson;
typedef struct {} _objc_exc_FCPerson;
#endif

struct FCPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_fcName;
};
struct NSObject_IMPL {
    Class isa;
};
static NSString * _I_FCPerson_fcName(FCPerson * self, SEL _cmd) { 
      return (*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName));
 }
static void _I_FCPerson_setFcName_(FCPerson * self, SEL _cmd, NSString *fcName) {
      (*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName)) = fcName; 
}

setter和getter在内存中读取属性的原理是什么?(*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName))是怎么找到fcName这个属性值的?
在取值时,系统只知道对象首地址,并不知道具体属性的地址信息。方法中(char *)self其实就是FCPerson对象的首地址,而OBJC_IVAR_$_FCPerson$_fcName则是fcName属性距离首地址的偏移量,系统就是通过首地址+偏移量的方式进行属性的读写的。

if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

Isa解析

通过initIsa进入到objc_object::initIsa方法中,首先看到的就是isa的初始化方法isa_t newisa(0);,具体看一下isa_t的内部实现,删除掉多余代码后:

union isa_t {
    uintptr_t bits;

private:
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

可以看到isa_t是一个联合体(联合体中成员互斥,即bits,cls,struct{ISA_BITFIELD}只能是其中一种),依次分析三个成员变量:

#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
#   if ISA_HAS_CXX_DTOR_BIT
        newisa.has_cxx_dtor = hasCxxDtor;
#   endif
        newisa.setClass(cls, this);
#endif
        newisa.extra_rc = 1;

因此,如果是nonPointerIsa的话,isa已经不再是一个单纯只想cls的指针了,携带了很多附加信息。

遗留问题

通过探究源码得知,initIsa方法写死的创建非nonPointerIsa, initInstanceIsa和initClass创建的是nonPointerIsa,具体原因以后研究完会继续补充~

上一篇 下一篇

猜你喜欢

热点阅读