返回

alloc究竟做了什么

IOS

从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;