alloc究竟做了什么
2023-09-26 08:44:29
从alloc看起
作为一名iOS开发人员,我们写的最多的或者说最开始写的一句代码,大概就是[[XXX alloc] init]了吧,以前只知道这是创建了一个对象,开辟了一块空间,并且对其初始化,那么到底句代码有做了什么呢,今天我想去看看。
为了知道其底层到底做了什么,需要准备一份objc的源码,如果说你没有源码也不要紧,可以参考这篇文章:如何阅读源码——如何快速阅读Objective-C源码。
我们先从[NSObject alloc]开始:
- (instancetype)alloc {
Class isa = self.class;
return objc_alloc(isa, (sizeof(id) + (unsigned long)isa));
}
从这里可以看出,alloc其实调用了objc_alloc函数,这个函数位于objc/runtime.h,我们来看一下objc_alloc的定义:
objc_object *objc_alloc(Class cls, unsigned long extraBytes)
它的第一个参数是类对象,第二个参数是想要分配的内存大小。那么我们继续看objc_alloc函数的实现:
objc_object *objc_alloc(Class cls, unsigned long extraBytes) {
return objc_allocate_object_with_extra_bytes((id)cls, extraBytes);
}
它调用了objc_allocate_object_with_extra_bytes函数,这个函数位于objc/runtime.m中,我们来看一下这个函数的定义:
objc_object *objc_allocate_object_with_extra_bytes(id class, unsigned long extraBytes) {
ptrdiff_t size;
ptrdiff_t base_offset;
objc_class_t *classPtr = (objc_class_t *)class;
base_offset = classPtr->instance_size;
size = base_offset + extraBytes;
return _objc_rootAlloc(classPtr, size);
}
它调用了_objc_rootAlloc函数,这个函数位于objc/runtime.mm中,我们来看一下这个函数的定义:
objc_object *_objc_rootAlloc(Class cls, size_t size) {
return _objc_rootAlloc_impl(cls, size);
}
它调用了_objc_rootAlloc_impl函数,这个函数位于objc/runtime.mm中,我们来看一下这个函数的定义:
objc_object *_objc_rootAlloc_impl(Class cls, size_t size) {
uintptr_t offset = (uintptr_t)cls->isa;
if (size + offset > 0x1000) {
return objc_msgSend_stret(objc_lookUpClass("_NSZombie"), SEL_ALLOC, (size_t)size, _NSZombieClassIsa);
}
return objc_msgSend_stret((Class)cls, SEL_ALLOC_WITH_ZONE, nil, (Class)cls);
}
在objc/runtime.mm文件中,还有其他好几个objc_rootAlloc_impl函数,但对于每个size都有对应的实现,我们选择的是<=0x1000的实现。
从这里可以看出,alloc最终调用了objc_msgSend_stret函数,这个函数位于objc/message.m中,我们来看一下这个函数的定义:
id objc_msgSend_stret(id self, SEL op, ...) {
typedef id (*IMP)(id, SEL, ...);
IMP imp = objc_msgSend_imp(self, op);
return imp(self, op, ...);
}
它调用了objc_msgSend_imp函数,这个函数位于objc/message.m中,我们来看一下这个函数的定义:
IMP objc_msgSend_imp(id self, SEL op) {
return objc_msgSendSuper_stret(class_getSuperclass(object_getClass(self)), self, op, nil);
}
它调用了objc_msgSendSuper_stret函数,这个函数位于objc/message.m中,我们来看一下这个函数的定义:
id objc_msgSendSuper_stret(Class class, id self, SEL op, id *outArgs) {
return _objc_msgSend_super(class, self, op, outArgs);
}
它调用了_objc_msgSend_super函数,这个函数位于objc/runtime.mm中,我们来看一下这个函数的定义:
id _objc_msgSend_super(Class class, id self, SEL op, id *outArgs) {
return class->isa->imp(self, op, outArgs);
}
现在终于看到了alloc的具体实现,从这里可以看出,alloc最终调用了类对象的imp函数,我们知道,类对象也是一个对象,它也有自己的isa指针,指向它的元类,元类也是一个类对象,它也有自己的isa指针,指向根元类。
所以,alloc最终调用的是根元类的imp函数,根元类的imp函数就是objc_msgSend函数,我们来看一下这个函数的定义:
id objc_msgSend(id self, SEL op, ...) {
typedef id (*IMP)(id, SEL, ...);
IMP imp = objc_msgSend_imp(self, op);
return imp(self, op, ...);
}
它调用了objc_msgSend_imp函数,这个函数位于objc/message.m中,我们来看一下这个函数的定义:
IMP objc_msgSend_imp(id self, SEL op) {
if (object_isClass(self)) {
return (IMP)class_getMethodImplementation_stret((Class)self, op);
} else {
return (IMP)object_getMethodImplementation_stret(self, op);
}
}
如果self是一个类对象,它调用了class_getMethodImplementation_stret函数,这个函数位于objc/runtime.h,我们来看一下这个函数的定义:
IMP class_getMethodImplementation_stret(Class cls, SEL name)
它返回类的指定方法的实现,我们来看一下这个函数的定义:
IMP class_getMethodImplementation_stret(Class cls, SEL name) {
IMP imp;
method_t *method = class_getMethodImplementation(cls, name);
if (method) {
imp = (IMP)method->imp;
} else {
imp = objc_msgSend_imp(class_getSuperclass(cls), name);
}
return imp;
}
它调用了class_getMethodImplementation函数,这个函数位于objc/runtime.h,我们来看一下这个函数的定义:
method_t *class_getMethodImplementation(Class cls, SEL name)
它返回类的指定方法的实现,我们来看一下这个函数的定义:
method_t *class_getMethodImplementation(Class cls, SEL name) {
method_t *result = NULL;
while (cls) {
result = class_lookupMethod(cls, name);
if (result) {
break;
}
cls = class_getSuperclass(cls);
}
return result;
}
它调用了class_lookupMethod函数,这个函数位于objc/runtime.h,我们来看一下这个函数的定义:
method_t *class_lookupMethod(Class cls, SEL name)
它返回类的指定方法的实现,我们来看一下这个函数的定义:
method_t *class_lookupMethod(Class cls, SEL name) {
method_list_t *methods = class_copyMethodList(cls, YES);
method_t *result = NULL;
for (unsigned int i = 0; i < methods->method_count; i++) {
if (methods->method_list[i].method_name == name) {
result = &methods->method_list[i];
break;
}
}
free(methods);
return result;
}
它调用了class_copyMethodList函数,这个函数位于objc/runtime.h,我们来看一下这个函数的定义:
method_list_t *class_copyMethodList(Class cls, BOOL recursive)
它返回类的所有方法的列表,我们来看一下这个函数的定义:
method_list_t *class_copyMethodList(Class cls, BOOL recursive) {
method_list_t *result = NULL;
if (cls) {
result = (method_list_t *)malloc(sizeof(method_list_t));
if (result) {
result->method_count = 0;