runtime-class创建过程(第一解)

我觉得作为一名程序员,不断去深入挖掘代码的底层实现过程,这是一件非常有意思的事情,就像福尔摩斯探案一样,层层解析,得以真相。
首先,看如下代码段:

#import 
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
      
        NSLog(@"Hello, World!");
        Person *son = [[Person alloc]init];
    }
    return 0;
}

在mian函数中,我们创建了一个Person的类,那么在执行[[Person alloc]init]这段代码时做了什么,下面一步步去看
1、使用clang进行编译,执行以下命令:

clang -rewrite-objc main.m 

2、执行上面代码后,会在目录文件下生成一个main.cpp文件


屏幕快照 2019-09-09 下午4.26.19.png

3、使用 open main.cpp命令打开文件,直接拉到文件底部,查看编译后的代码内容

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_cl_snxcxfl91ss0gvkz5wvcksjc0000gn_T_main_895957_mi_0);
        Poson *son = ((Poson *(*)(id, SEL))(void *)objc_msgSend)((id)((Poson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Poson"), sel_registerName("alloc")), sel_registerName("init"));
    }
    return 0;
}

开始源码查看

可以看到代码已经被转换,而之前

 [[Person alloc]init]

已经变成

((Poson *(*)(id, SEL))(void *)objc_msgSend)((id)((Poson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Poson"), sel_registerName("alloc")), sel_registerName("init"));

1、调用objc_msgSend发送消息

((Poson *(*)(id, SEL))(void *)objc_msgSend)

2、分别调用objc_getClass和sel_registerName两个方法

((id)objc_getClass("Poson"), sel_registerName("alloc")), sel_registerName("init"))

可以看到,调用了两个runtime方法,分别是:objc_getClass("Poson")和sel_registerName("alloc")
关系如下:

runtime-class创建过程(第一解)_第1张图片
屏幕快照 2019-09-09 下午4.39.13.png

方法注册了两次,是因为alloc与init两个方法的调用。
3、查看objc_getClass方法的实现,从[[ https://opensource.apple.com/tarballs/objc4/]下载源码,进入到 objc-runtime.mm文件,搜索objc_getClass跳转到代码块,看到如下代码

Class objc_getClass(const char *aClassName)
{
    if (!aClassName) return Nil;

    // NO unconnected, YES class handler
    return look_up_class(aClassName, NO, YES);
}

4、关键是看look_up_class这个方法,这个方法的实现如下:

Class 
look_up_class(const char *name, 
              bool includeUnconnected __attribute__((unused)), 
              bool includeClassHandler __attribute__((unused)))
{
    if (!name) return nil;

    Class result;
    bool unrealized;
    {
        mutex_locker_t lock(runtimeLock);
        result = getClass(name);
        unrealized = result  &&  !result->isRealized();
    }
    if (unrealized) {
        mutex_locker_t lock(runtimeLock);
        realizeClass(result);
    }
    return result;
}

5、进入到realizeClass(result);方法,看它做了什么,这才是正菜

static Class realizeClass(Class cls)
{
    runtimeLock.assertLocked();

    const class_ro_t *ro;
    class_rw_t *rw;
    Class supercls;
    Class metacls;
    bool isMeta;

    if (!cls) return nil;//如果参数为空,返回空
    if (cls->isRealized()) return cls;//如果类已实现,返回类
    assert(cls == remapClass(cls));

    // fixme verify class is not in an un-dlopened part of the shared cache?

    ro = (const class_ro_t *)cls->data();
    if (ro->flags & RO_FUTURE) {
        // This was a future class. rw data is already allocated.表示rw已经分配
        rw = cls->data();
        ro = cls->data()->ro;
        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
    } else {
        // Normal class. Allocate writeable class data.
        rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
        rw->ro = ro;
        rw->flags = RW_REALIZED|RW_REALIZING;
        cls->setData(rw);
    }

    isMeta = ro->flags & RO_META;

    rw->version = isMeta ? 7 : 0;  // old runtime went up to 6


    // Choose an index for this class.
    // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
    cls->chooseClassArrayIndex();

    if (PrintConnecting) {
        _objc_inform("CLASS: realizing class '%s'%s %p %p #%u", 
                     cls->nameForLogging(), isMeta ? " (meta)" : "", 
                     (void*)cls, ro, cls->classArrayIndex());
    }

    // Realize superclass and metaclass, if they aren't already.
    // This needs to be done after RW_REALIZED is set above, for root classes.
    // This needs to be done after class index is chosen, for root metaclasses.
    supercls = realizeClass(remapClass(cls->superclass));
    metacls = realizeClass(remapClass(cls->ISA()));

#if SUPPORT_NONPOINTER_ISA
    // Disable non-pointer isa for some classes and/or platforms.
    // Set instancesRequireRawIsa.
    bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
    bool rawIsaIsInherited = false;
    static bool hackedDispatch = false;

    if (DisableNonpointerIsa) {
        // Non-pointer isa disabled by environment or app SDK version
        instancesRequireRawIsa = true;
    }
    else if (!hackedDispatch  &&  !(ro->flags & RO_META)  &&  
             0 == strcmp(ro->name, "OS_object")) 
    {
        // hack for libdispatch et al - isa also acts as vtable pointer
        hackedDispatch = true;
        instancesRequireRawIsa = true;
    }
    else if (supercls  &&  supercls->superclass  &&  
             supercls->instancesRequireRawIsa()) 
    {
        // This is also propagated by addSubclass() 
        // but nonpointer isa setup needs it earlier.
        // Special case: instancesRequireRawIsa does not propagate 
        // from root class to root metaclass
        instancesRequireRawIsa = true;
        rawIsaIsInherited = true;
    }
    
    if (instancesRequireRawIsa) {
        cls->setInstancesRequireRawIsa(rawIsaIsInherited);
    }
// SUPPORT_NONPOINTER_ISA
#endif

    // Update superclass and metaclass in case of remapping
    cls->superclass = supercls;
    cls->initClassIsa(metacls);

    // Reconcile instance variable offsets / layout.
    // This may reallocate class_ro_t, updating our ro variable.
    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);

    // Set fastInstanceSize if it wasn't set already.
    cls->setInstanceSize(ro->instanceSize);

    // Copy some flags from ro to rw
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }

    // Connect this class to its superclass's subclass lists
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }

    // Attach categories
    methodizeClass(cls);//分类设置

    return cls;
}

realizeClass方法实现

1、创建了五个变量

    const class_ro_t *ro; //保存着类的基本属性
    class_rw_t *rw; // 里面有个 class_ro_t对象,
    Class supercls;
    Class metacls;
    bool isMeta;

先简单了解一下Class对象的结构,每个objc_class都包含有class_data_bits_t数据位,其中储存了class_rw_t的指针地址和一些其他标记。class_rw_t中包含有属性方法协议列表,以及class_ro_t指针地址。而在class_ro_t结构中,储存的是编译器决定的属性方法协议
2、两个逻辑判断

    if (!cls) return nil;//如果参数为空,返回空
    if (cls->isRealized()) return cls;//如果类已实现,返回类

3、一个断言,主要依据是当前类等于remapClass(cls)就直接退出
4、通过(const class_ro_t *)cls->data()获取一个class_ro_t对象赋值给定义的ro;

ro = (const class_ro_t *)cls->data();//获取一个class的class_ro_t对象,用于判断

5、如果ro-flags已标记了,但是没有实现,则给rw和ro分别读取cls相应值

       rw = cls->data();
        ro = cls->data()->ro;
        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);

如果没有被标记则:

        rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);//创建一个class_rw_t对象
        rw->ro = ro;//将ro赋值给rw.ro,ro = (const class_ro_t *)cls->data();
        rw->flags = RW_REALIZED|RW_REALIZING;
        cls->setData(rw);//设置累的data

6、接下来就是

 // Update superclass and metaclass in case of remapping
    cls->superclass = supercls;
    cls->initClassIsa(metacls);//获取isa指针

    // Reconcile instance variable offsets / layout.
    // This may reallocate class_ro_t, updating our ro variable.
    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);

    // Set fastInstanceSize if it wasn't set already.
    cls->setInstanceSize(ro->instanceSize);

    // Copy some flags from ro to rw
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }

    // Connect this class to its superclass's subclass lists
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }

    // Attach categories
    methodizeClass(cls);//分类设置

最后调用的methodizeClass是使用分类时用的。

总结:

大体过了一遍创建流程,由于理解的还不是很深入,写的不是很透彻,再接再厉,加油!
参考资料:
https://www.cnblogs.com/vanch/p/9662424.html
https://segmentfault.com/a/1190000004992561
https://www.jianshu.com/p/3019605a4fc9

你可能感兴趣的:(runtime-class创建过程(第一解))