美文网首页iOS-Developer-OC
iOS:弄懂OC中的类与元类

iOS:弄懂OC中的类与元类

作者: 三十六_ | 来源:发表于2018-05-08 15:07 被阅读52次

    首先,来看看什么是类。类在OC中其实是一个指向objc_class的结构体指针,结构体的构造为:

    typedef struct objc_class *Class;
    struct objc_class {
            Class isa  OBJC_ISA_AVAILABILITY;
            #if !__OBJC2__
            Class super_class                       OBJC2_UNAVAILABLE;  // 父类
            const char *name                        OBJC2_UNAVAILABLE;  // 类名
            long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
            long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
            long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
            struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
            struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
            struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
            struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
            #endif
    } OBJC2_UNAVAILABLE;
    

    OC中对象的定义是这样的:

    typedef struct objc_object {
        Class isa;
    } *id;
    

    每个对象都有一个类,在Objective-C中,对象的类是isa指针决定的,即 isa 指针指向对象所属的类。
    OC对象有一个大家都熟悉的特性:消息发送机制

    [@"stringTest" stringByAppendingString:@"text"];
    

    原理是OC对象在发送消息时,运行时库会追寻着对象的isa指针得到对象所属的类(这儿是NSString类)。这个类包含了能应用于这个类的所有实例方法以及指向父类的指针,以便可以找到父类的实例方法。运行时库检查这个类和其父类的方法列表,找到与消息对应的方法(在上面的代码里,是NSString类的stringByAppendingString:方法)。编译器会将消息转换为消息函数objc_msgSend进行调用。
    我们平时在写代码时也会对类发送消息:

    NSString *testString = [NSString stringWithFormat:@"%d,%s",3, "test"];
    

    从这里可以知道,OC的类其实也是一个对象,一个对象就要有一个它属于的类,意味着类也要有一个 isa 指针,指向他所属的类。那么元类的类是什么?就是我们所说的元类 (MetaClass) ,所以,元类就是类所属的类。从消息机制的层面来说:

    当你给对象发送消息时,消息是在寻找这个对象的类的方法列表。
    当你给类发消息时,消息是在寻找这个类的元类的方法列表。

    既然元类是个类,和之前的类一样也是一个对象,那元类的类是什么呢?
    所有的元类都使用根元类作为他们的类。这就意味着所有NSObject的子类(大多数类)的元类都会以NSObject的元类作为他们的类,根元类的 isa 指针指向了它自己:


    image.png

    当我们运行时创建类时:

    Class newClass  = objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);
    class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
    objc_registerClassPair(newClass);
    

    上面的代码创建了一个NSError的子类,我们可以看到创建函数objc_allocateClassPair() 只有一个返回值,返回一个类,但是注意它的名称ClassPair,应该是一对才符合函数名所表达的意思啊,一个作为返回值了,那另一个呢?没错,另一个就是元类。这也体现了OC可以在运行时创建类的强大之处。

    相关文章

      网友评论

        本文标题:iOS:弄懂OC中的类与元类

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