美文网首页
iOS Runtime(一)------类和对象的本质

iOS Runtime(一)------类和对象的本质

作者: Felix_ | 来源:发表于2018-11-06 10:36 被阅读11次

    在面向对象的语言中,类和对象是我们接触最多的东西,那么在iOS中类和对象到底是什么样的?方法调用是怎么实现的?标题为Runtime,跟类和对象有什么关系呢?不要着急,跟着我的思路,开始认识iOS中类和对象的本质。
    首先我们在<objc/objc.h>中找到如下定义:

    typedef struct objc_class *Class;
    struct objc_object {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    typedef struct objc_object *id;
    

    <objc/runtime.h>中找到如下定义:

    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    
    } OBJC2_UNAVAILABLE;
    

    结合起来不难发现,类其实是就是一个指向结构体的指针,而对象其实就是一个指向struct objc_object的指针,它里面的isa指针指向他的类对象,引用网络上的一个图


    通过这个图我们先大概的理解一下,对象```的```isa```指向其```类(或者叫类对象)```,```类isa指向元类,而元类的isa指向根元类根元类isa则指向自身
    但是这张图仅仅是理论,那么实际是什么样子的呢?

    Talk is cheap. Show me the code

    废话不多说,上代码:

    /**=======================================*/
    @interface GrandFather:NSObject
    @end
    @implementation GrandFather
    @end
    /**=======================================*/
    @interface Father:GrandFather
    @end
    @implementation Father
    @end
    /**=======================================*/
    @interface Son:Father
    @end
    @implementation Son
    @end
    

    接下来我们来打印下细节(为了更加清晰,没有使用循环)

        Son *son = [[Son alloc] init];
        
        Class sonISA = object_getClass(son);
        Class sonClass = [sonISA class];
        
        Class sonClassISA = object_getClass(sonClass);
        Class sonClassClass = [sonClassISA class];
        
        Class sonClassClassISA = object_getClass(sonClassClass);
        Class sonClassClassClass = [sonClassClassISA class];
        
        Class sonClassClassClassISA = object_getClass(sonClassClassClass);
        Class sonClassClassClassClass = [sonClassClassClassISA class];
        NSLog(@"============Son Info============");
        NSLog(@"Son instance address:%p",son);
        
        NSLog(@"Son instance isa:%@------%p",NSStringFromClass(sonISA),sonISA);
        NSLog(@"Son Class:%@------%p",NSStringFromClass(sonClass),sonClass);
        NSLog(@"%@",class_isMetaClass(sonClass)?@"元类":@"非元类");
        
        NSLog(@"Son Class isa:%@------%p",NSStringFromClass(sonClassISA),sonClassISA);
        NSLog(@"Son Class Class:%@------%p",NSStringFromClass(sonClassClass),sonClassClass);
        NSLog(@"%@",class_isMetaClass(sonClassClass)?@"元类":@"非元类");
        
        NSLog(@"Son Class Class isa:%@------%p",NSStringFromClass(sonClassClassISA),sonClassClassISA);
        NSLog(@"Son Class Class Class:%@------%p",NSStringFromClass(sonClassClassClass),sonClassClassClass);
        NSLog(@"%@",class_isMetaClass(sonClassClassClass)?@"元类":@"非元类");
        
        NSLog(@"Son Class Class Class isa:%@------%p",NSStringFromClass(sonClassClassClassISA),sonClassClassClassISA);
        NSLog(@"Son Class Class Class Class:%@------%p",NSStringFromClass(sonClassClassClassClass),sonClassClassClassClass);
        NSLog(@"%@",class_isMetaClass(sonClassClassClassClass)?@"元类":@"非元类");
        
        Father *father = [[Father alloc] init];
        
        Class fatherISA = object_getClass(father);
        Class fatherClass = [fatherISA class];
        
        Class fatherClassISA = object_getClass(fatherClass);
        Class fatherClassClass = [fatherClassISA class];
        
        Class fatherClassClassISA = object_getClass(fatherClassClass);
        Class fatherClassClassClass = [fatherClassClassISA class];
        
        Class fatherClassClassClassISA = object_getClass(fatherClassClassClass);
        Class fatherClassClassClassClass = [fatherClassClassClassISA class];
        NSLog(@"============Father Info============");
        NSLog(@"Father instance address:%p",father);
        
        NSLog(@"Father instance isa:%@------%p",NSStringFromClass(fatherISA),fatherISA);
        NSLog(@"Father Class:%@------%p",NSStringFromClass(fatherClass),fatherClass);
        NSLog(@"%@",class_isMetaClass(fatherClass)?@"元类":@"非元类");
        
        NSLog(@"Father Class isa:%@------%p",NSStringFromClass(fatherClassISA),fatherClassISA);
        NSLog(@"Father Class Class:%@------%p",NSStringFromClass(fatherClassClass),fatherClassClass);
        NSLog(@"%@",class_isMetaClass(fatherClassClass)?@"元类":@"非元类");
        
        NSLog(@"Father Class Class isa:%@------%p",NSStringFromClass(fatherClassClassISA),fatherClassClassISA);
        NSLog(@"Father Class Class Class:%@------%p",NSStringFromClass(fatherClassClassClassClass),fatherClassClassClassClass);
        NSLog(@"%@",class_isMetaClass(fatherClassClassClassClass)?@"元类":@"非元类");
        
        NSLog(@"Father Class Class Class isa:%@------%p",NSStringFromClass(fatherClassClassClassISA),fatherClassClassClassISA);
        NSLog(@"Father Class Class Class Class:%@------%p",NSStringFromClass(fatherClassClassClassClass),fatherClassClassClassClass);
        NSLog(@"%@",class_isMetaClass(fatherClassClassClassClass)?@"元类":@"非元类");
        
        GrandFather *grandFather = [[GrandFather alloc] init];
        
        Class grandFatherISA = object_getClass(grandFather);
        Class grandFatherClass = [grandFatherISA class];
        
        Class grandFatherClassISA = object_getClass(grandFatherClass);
        Class grandFatherClassClass = [grandFatherClassISA class];
        
        Class grandFatherClassClassISA = object_getClass(grandFatherClassClass);
        Class grandFatherClassClassClass = [grandFatherClassClassISA class];
        
        Class grandFatherClassClassClassISA = object_getClass(grandFatherClassClassClass);
        Class grandFatherClassClassClassClass = [grandFatherClassClassClassISA class];
        NSLog(@"============GrandFather Info============");
        NSLog(@"GrandFather instance address:%p",grandFather);
        
        NSLog(@"GrandFather instance isa:%@------%p",NSStringFromClass(grandFatherISA),grandFatherISA);
        NSLog(@"GrandFather Class:%@------%p",NSStringFromClass(grandFatherClass),grandFatherClass);
        NSLog(@"%@",class_isMetaClass(grandFatherClass)?@"元类":@"非元类");
        
        NSLog(@"GrandFather Class isa:%@------%p",NSStringFromClass(grandFatherClassISA),grandFatherClassISA);
        NSLog(@"GrandFather Class Class:%@------%p",NSStringFromClass(grandFatherClassClass),grandFatherClassClass);
        NSLog(@"%@",class_isMetaClass(grandFatherClassClass)?@"元类":@"非元类");
        
        NSLog(@"GrandFather Class Class isa:%@------%p",NSStringFromClass(grandFatherClassClassISA),grandFatherClassClassISA);
        NSLog(@"GrandFather Class Class Class:%@------%p",NSStringFromClass(grandFatherClassClassClass),grandFatherClassClassClass);
        NSLog(@"%@",class_isMetaClass(grandFatherClassClassClass)?@"元类":@"非元类");
        
        NSLog(@"GrandFather Class Class Class isa:%@------%p",NSStringFromClass(grandFatherClassClassClassISA),grandFatherClassClassClassISA);
        NSLog(@"GrandFather Class Class Class Class:%@------%p",NSStringFromClass(grandFatherClassClassClassClass),grandFatherClassClassClassClass);
        NSLog(@"%@",class_isMetaClass(grandFatherClassClassClassClass)?@"元类":@"非元类");
    

    在这里,我们分别创建了sonfathergrandFather三个对象,并且分别打印了对象的地址,对象的isa指向的Class的地址,类(类对象)的地址等,结果如下

    ============Son Info============
    Son instance address:0x60c00002c980
    Son instance isa:Son------0x104d614a0
    Son Class:Son------0x104d614a0
    非元类
    Son Class isa:Son------0x104d61478
    Son Class Class:Son------0x104d61478
    元类
    Son Class Class isa:NSObject------0x105d0de58
    Son Class Class Class:NSObject------0x105d0de58
    元类
    Son Class Class Class isa:NSObject------0x105d0de58
    Son Class Class Class Class:NSObject------0x105d0de58
    元类
    ============Father Info============
    Father instance address:0x60c000003e40
    Father instance isa:Father------0x104d61450
    Father Class:Father------0x104d61450
    非元类
    Father Class isa:Father------0x104d61428
    Father Class Class:Father------0x104d61428
    元类
    Father Class Class isa:NSObject------0x105d0de58
    Father Class Class Class:NSObject------0x105d0de58
    元类
    Father Class Class Class isa:NSObject------0x105d0de58
    Father Class Class Class Class:NSObject------0x105d0de58
    元类
    ============GrandFather Info============
    GrandFather instance address:0x60c000003de0
    GrandFather instance isa:GrandFather------0x104d61400
    GrandFather Class:GrandFather------0x104d61400
    非元类
    GrandFather Class isa:GrandFather------0x104d613d8
    GrandFather Class Class:GrandFather------0x104d613d8
    元类
    GrandFather Class Class isa:NSObject------0x105d0de58
    GrandFather Class Class Class:NSObject------0x105d0de58
    元类
    GrandFather Class Class Class isa:NSObject------0x105d0de58
    GrandFather Class Class Class Class:NSObject------0x105d0de58
    元类
    

    这个结果和我们上面的图基本就可以对应起来了:

    对象的isa指向类(或者叫类对象)
    类的isa指向元类
    元类的isa指向根元类
    根元类的isa指向自身

    那么什么是元类呢?

    通过上面的描述,我们知道,其实类自身也是一个对象,那么类对象为什么能够调用方法呢?这里我们就要提一下方法调用的流程了
    通过对象的isa指针找到他的类
    在类的method list中查找方法
    如果没有找到该方法,继续前往父类中查找
    直到查找到该方法,才去执行方法
    所以,类对象调用方法的也会去通过它的isa查找它所属的类,也就是所谓的元类。
    好,接下来我们来分析一下objc_class里面的各个成员

    objc_class -> isa

    这个isa用来指向其所属的类

    objc_class -> super_class

    super_class用来指向其父类

    objc_class -> name

    类的名称

    objc_class -> version

    类的版本

    objc_class -> info

    类的信息

    objc_class -> instance_size

    实例的大小

    objc_class -> ivars

    实例变量列表

    objc_class -> methodLists

    方法列表,我们看下MethodOC里的结构

    typedef struct objc_method *Method;
    struct objc_method {
        SEL method_name                                          OBJC2_UNAVAILABLE;
        char *method_types                                       OBJC2_UNAVAILABLE;
        IMP method_imp                                           OBJC2_UNAVAILABLE;
    }
    

    里面包含了SELmethod_typeIMP

    objc_class -> cache

    缓存列表

    objc_class -> protocols

    协议列表

    相关文章

      网友评论

          本文标题:iOS Runtime(一)------类和对象的本质

          本文链接:https://www.haomeiwen.com/subject/olnjxqtx.html