Objective-C Runtime:类与对象

作者: 繁华落尽丶lee | 来源:发表于2016-07-26 10:00 被阅读58次

    学习笔记整理

    Objective-C

    Objective-C是一门动态语言。其实Objecitve-C扩展了C语言,加入了面向对象特性和消息传递机制。简单的说,这个扩展的核心是Runtime库,它是Objective-C面向对象的和动态机制的基石。Objective-C是动态的语言,意味着它不仅需要一个编译器,还需要一个运行时系统动态的创建类和对象、进行消息传递和转发。充分理解Runtime机制,可以帮助我们更好的学习Objective-C。下面一起学习Runtime:


    类(Class)

    在Objective-C中,类和对象都是结构体。从头文件objc/objc.h中,可以查看定义。

    typedef struct objc_class *Class;
    

    查看objc/runtime.h中objc_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;//
        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;
    

    其中
    1.isa:指向metaClass(元类)的指针。
    2.super_class:执行该类的父类,如果该类是根类(NSObject或NSProxy),则super_class为NULL。
    3.version:记录类的版本信息。主要用于对象的序列化,可以通过它识别出不同定义版本中实例变量布局的改变。
    4.cache:用于缓存常用的方法。当接收对象收到消息时,根据isa指针去查找相应的对象。实际上,这个对象中有很多方法,只有一少部分经常使用,很多方法不能使用或者根本用不上。这种情况下,如果每次接收到消息都去遍历methodLists,性能较差,所以使用cache保存经常使用的方法,在接收到消息后,首先查找cache,如果没有则查找methodLists,提高查找效率。

    对象

    在objc/objc.h中,对象的定义

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

    objc_object是一个类的实例的结构体,其中只有一个指向其类的isa指针。当对象发送消息是,运行时库可以根据isa指针找到实例对象所属的类。运行时库会在类的methodLists和父类的methodLists中查找能响应的方法,找到后运行方法。

    另外,id是objc_object类型的指针。通过它可以实现类似C++的泛型。

    元类(Meta Class)

    所有类自身也是一个对象,所以我们可以向类发送消息(调用类方法)。例如,

    NSArray *array = [NSArray array];
    

    +array消息发送给NSArray类,因为NSArray也是对象,所以它也是objc_object结构体,包含isa指针指向其类。那么,isa指针指向哪里呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的objc_object结构体。所以就引出了meta-class是一个类对象的类
    当向一个对象发送消息时,会在这个类的方法列表中查找方法;
    当向一个类发送消息时,会在这个类的meta-class的方法列表中查找。meta-class 中存放着一个类所有的类方法。

    这时可能又发现了一个问题,既然一切皆是类,那么meta-class的isa指针指向哪里呢?在Objective-C设计者为了防止无限循环,所有的meta-class的isa指向基类的meta-class,基类的meta-class指向自身。


    1413628797629491.png

    上图,虚线是isa的指向,可以看出每个isa都不为空,所以无论什么类型的对象,我们都可以通过isa获取对象信息。实线是superclass指向,通过该它可以方便查找父类,如果是根类在superclass为空。

    常用操作

    //类名
    const char * class_getName(Class cls);
    
    //父类
    Class class_getSuperclass(Class cls);
    
    //判断是否为元类
    BOOL class_isMetaClass(Class cls);
    
    //实例大小
    size_t class_getInstanceSize(Class cls);
    

    成员变量(ivars)及属性
    在objc_class中,所有的成员变量、属性的信息是放在链表ivars中。ivars是数组,存放着指向每个元素的Ivar指针。以下方法是操作这个字段的。

    成员变量操作方法

    // 获取类中指定名称实例成员变量的信息
    Ivar class_getInstanceVariable ( Class cls, const char *name );
    
    // 获取类成员变量的信息
    Ivar class_getClassVariable ( Class cls, const char *name );
    
    // 添加成员变量
    BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
    
    // 获取整个成员变量列表
    Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
    

    注意:class_copyIvarList需要手动释放free();
    属性操作方法

    // 获取指定的属性
    objc_property_t class_getProperty ( Class cls, const char *name );
    
    // 获取属性列表
    objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
    
    // 为类添加属性
    BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    
    // 替换类的属性
    void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    

    方法(methodLists)

    // 添加方法
    BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
    
    // 获取实例方法
    Method class_getInstanceMethod ( Class cls, SEL name );
    
    // 获取类方法
    Method class_getClassMethod ( Class cls, SEL name );
    
    // 获取所有方法的数组
    Method * class_copyMethodList ( Class cls, unsigned int *outCount );
    
    // 替代方法的实现
    IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
    
    // 返回方法的具体实现
    IMP class_getMethodImplementation ( Class cls, SEL name );
    IMP class_getMethodImplementation_stret ( Class cls, SEL name );
    
    // 类实例是否响应指定的selector
    BOOL class_respondsToSelector ( Class cls, SEL sel );
    
    • class_addMethod方法可以覆盖父类方法的实现,但是不会取代本类已存在的实现,如果存在同名的方法,则会返回NO。如果要修改本类中方法的实现,可以使用method_setImplementation。

    • class_getInstanceMethod,class_getClassMethod方法和class_copyMethodList不同,前者会搜索父类。

    • class_replaceMethod如果类中存在同名的,则会替换;如果不存在,会添加。

    • class_getMethodImplementation方法,该函数再向类实例发送消息是会调用,并返回一个指向方法实现的函数指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针是一个指向runtime内部的函数,而不一定是方法的实际实现。

    • class_respondsToSelector函数,通常使用NSObject类的respondsToSelector:或instancesRespondToSelector:方法来实现相同目的。

    如果想看具体内容点这里

    小结

    本文介绍了Runtime运行时中类和对象相关的数据结构,通过数据结构可以更好的理解底层面向对象的实现。另外,列举了一些常用的操作方法。

    参考资料:

    1.Objective-C 中的类和对象 - Garan no Dou
    2.What is a meta-class in Objective-C?
    3.Objective-C Runtime - Apple
    4.Objective-C Runtime 运行时之一:类与对象

    相关文章

      网友评论

        本文标题:Objective-C Runtime:类与对象

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