前期准备
下载 objc 源码,创建可断点调试工程,参考下面的文章
github.com/LGCooci/obj…
alloc流程图
验证过程
我们在 alloc 前打上断点,然后顺着 alloc 一路点进去
+ (id)alloc {
return _objc_rootAlloc(self);
}
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
在 callAlloc 函数,我们打上三个断点,便于调试。点击 continue,进入下一个断点,如图。
我们可以看到,在调用 callAlloc 之前,还调用了一个函数
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
继续 continue,又进到了callAlloc 函数,但是这次进入到了 _objc_rootAllocWithZone,继续 _class_createInstancesFromZone
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
// allocWithZone under __OBJC2__ ignores the zone parameter
return _class_createInstanceFromZone(cls, 0, nil,
OBJECT_CONSTRUCT_CALL_BADALLOC);
}
unsigned
_class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,
id *results, unsigned num_requested)
{
unsigned num_allocated;
if (!cls) return 0;
size_t size = cls->instanceSize(extraBytes);
num_allocated =
malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()),
size, (void**)results, num_requested);
for (unsigned i = 0; i < num_allocated; i++) {
bzero(results[i], size);
}
// Construct each object, and delete any that fail construction.
unsigned shift = 0;
bool ctor = cls->hasCxxCtor();
for (unsigned i = 0; i < num_allocated; i++) {
id obj = results[i];
obj->initIsa(cls); // fixme allow nonpointer
if (ctor) {
obj = object_cxxConstructFromClass(obj, cls,
OBJECT_CONSTRUCT_FREE_ONFAILURE);
}
if (obj) {
results[i-shift] = obj;
} else {
shift++;
}
}
return num_allocated - shift;
}
_class_createInstancesFromZone 函数有三个重点函数
instanceSize 获取当前类所需字节数,进行 16 字节对齐
calloc 为当前类开辟的内存
initInstanceIsa 将当前类的信息和开辟的内存进行关联
以下为debug证实
此时内存开辟了,但是 obj 还是 id 类型,没有当前类的信息。继续下一步
initInstanceIsa 函数将当前类信息与开辟的内存进行关联,已经是我们要创建的类了。
NSObject 特性
NSObject *objc = [NSObject alloc];
第一次执行到 callAlloc,满足条件,直接调用了 _objc_rootAllocWithZone, 没有调用 +alloc。
判断条件源码如下:
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
}
bool hasCustomAWZ() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
// class or superclass has default alloc/allocWithZone: implementation
// Note this is is stored in the metaclass.
#define FAST_CACHE_HAS_DEFAULT_AWZ (1<<14)
执行流程如下图