前言
在iOS开发过程中,最最常见的就是类、对象。分析isa
对理解OC类、对象是非常重要的。
一、准备
1、我们先准备一个main.m
文件,内容如下
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSObject *objc1 = [[NSObject alloc] init];
NSLog(@"Hello, World! %@",objc1);
}
return 0;
}
使用我们编译器前端clang
命令来将main.m
重写成main.cpp
,命令如下
$clang -rewrite-objc main.m -o main.cpp
当然你也可以将这个main.m
编译成一个可执行文件命令如下
$clang -fobjc-arc -framework Foundation main.m -o main
$./main
//将会打印输出类似 Hello, World! <NSObject: 0x7f9eb1504220>
2、下载我们的OC的objc
源码,下载链接:objc4
二、分析
1、我们首先分析main.cpp
文件,先找到他的入口main
函数,一般在文件最后
- 这不跟我们的文件很像吗,我们可以在当前文件找到
NSObject
的定义
在这里由图可知NSObject
是一个objc_object
结构体的类型;我们继续找找就可以发现
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
咦,这里发现了一个Class
类型的isa
;
- 那我们找找
Class
又是个什么鬼?我们又在当前文件找找,原来他的定义大体如下
typedef struct objc_class *Class;
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
.....//此处省略很多函数代码
}
Class
是一个指向结构体objc_class
的指针
类型.并且还注意到,objc_class
居然继承于objc_object
,里面还有一个Class
类型的superclass
。
-
讲到这里大家是不是很晕啊,我也是。我们不妨先画一张简单的图,记录一下。
2、刚才是我们分析main.cpp
得到的一些信息,接下来我们需要分析objc
源码了,看看代码在运行的时候都是怎样指向绑定的。
- 在我的前面博客中iOS 底层探索- alloc流程中指出
在alloc最后的流程中是
static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
int construct_flags = OBJECT_CONSTRUCT_NONE,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
ASSERT(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size;
// 1:要开辟多少内存
size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
// 2;怎么去申请内存
obj = (id)calloc(1, size);
}
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
// 3: 绑定isa
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);
}
if (fastpath(!hasCxxCtor)) {
return obj;
}
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
1、计算内存;2、开辟内存;3,绑定isa。
我们看到最后的alloc的返回是 一个id
的类型
id
类型又是什么呢?我们在objc.h
找到定义。中文意思就是一个指向class
实例的指针;根据代码是指向类型objc_object
的指针
类型
/// A pointer to an instance of a class.
typedef struct objc_object *id;
到这里我们可以得出一条结论:
所有`NSObject`或其子类的`alloc`的方法返回出的类型都是`objc_object *`类型即`id`类型,
不过我们可以看到这里的返回出来的对象其实就是代码里面声明的id obj
,我们要看的isa的初始化,其实就在initInstanceIsa
这个函数中
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
接下来去initIsa
看看,
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_t
的newisa
,类型isa_t结构定义如下
# 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)
....
....
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
我的天啊,他是一个联合体,苹果粑粑可真会设计。不过我们可以看到
isa_t
有两个互斥属性cls
和bits
,并且bits
可按位分解为9个子属性.
下面有一张图可以参考一下
通过宏定义分析SUPPORT_INDEXED_ISA
#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
我们可以的到在arm64的iphone设备上 SUPPORT_INDEXED_ISA=0
,
所以知道newisa的会按照联合体的逻辑分配
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;
3、我们看一下objc_object
的isa
getter函数
inline Class
objc_object::getIsa()
{
return ISA();
}
....
....
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
}
根据前序推理得知在arm64的iphone 上会返回(Class)(isa.bits & ISA_MASK);
这个不就是newisa.shiftcls所包含的内容吗(注意,这两个并不相等;一个是64位,一个是64位中的部分)。
根据前面的1、2、3
得出:这个实例(objc_object
)的isa
是指向了当前的类(objc_class
).
这不就是前面画的实例对象isa和类对象的简单关系图
吗。
三、总结
1、在目前普遍的机型中arm64或者arm64s,isa是一个联合体类型;
2、实例对象objc_object
当调用isa
时,其实是调用isa
的getter函数ISA()
,返回联合体中的(Class)(isa.bits & ISA_MASK);
其具体值直线的是类对象objc_class
提问:
这里有一个实例对象isa和类对象的简单关系图
;不过我们看到类对象objc_class
他是继承于objc_object
应该也有一个isa
,那它的isa
是指向哪里的呢?并且它中间还有一个Class
类型(即objc_class *
)的supclass又是指向哪呢?
请听下回分解.