美文网首页
runtime概述

runtime概述

作者: vicentwyh | 来源:发表于2018-06-14 11:31 被阅读0次

    OC中runtime.h包含了OC中使用的一系列的底层C语言API声明

    类的结构

    typedef struct objc_class *Class; // 此声明在objc.h文件中
    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY; 指向类
    
    #if !__OBJC2__
        Class _Nullable super_class     指向父类                          
        const char * _Nonnull name      类名                            
        long version                    版本相关信息,默认为0            
        long info                       提供运行期使用的标示符             
        long instance_size              当前类实例变量的大小                                 
        struct objc_ivar_list * _Nullable ivars                  成员变量列表
        struct objc_method_list * _Nullable * _Nullable methodLists  类中的方法相关信息列表       
        struct objc_cache * _Nonnull cache                       调用过的方法的相关信息列表               
        struct objc_protocol_list * _Nullable protocols          遵循的协议信息列表
    #endif
    
    } OBJC2_UNAVAILABLE;
    

    可以看出:
    1.Class是指向struct objc_class结构体类型的结构体指针
    2.Class内部包含了指向对象类的isa指针和指向父类的super_class指针
    3.ivars是指向objc_ivar_list结构体的指针,objc_ivar_list结构如下:

    struct objc_ivar {
        char * _Nullable ivar_name        成员变量名                     
        char * _Nullable ivar_type        成员变量类型                     
        int ivar_offset                   指针偏移量             
    #ifdef __LP64__
        int space                        占用的内存空间                        
    #endif
    }                                                           
    
    struct objc_ivar_list {
        int ivar_count                                          
    #ifdef __LP64__
        int space                                               
    #endif
        /* variable length structure */
        struct objc_ivar ivar_list[1]                            
    }                                                            
    
    

    很显然ivars是个链表,内部包含了指向类中成员变量名称和成员变量类型的节点。
    4.methodLists 也是链表,存储类中的方法相关信息,objc_method_list的结构在runtime.h中也能找到,这里不在展示。
    5.cache链表:存储曾经调用过的方法的相关信息,这样将常用方法存到cache中,可以提高方法的查找效率。
    6.protocols链表:存储当前类(包括父类)遵守的协议的相关信息。

    底层函数

    // 返回对象的副本
    id object_copy(id obj, size_t size); 
    
    // 释放对象占用的内存
    id object_dispose(id obj);
    
    // 返回对象的类
    Class object_getClass(id obj);
    
    // 设置对象的类型,并返回类型
    Class object_setClass(id obj, Class cls);
    
    // 判断对象是否是类或元类
    BOOL object_isClass(id obj);
    
    // 获取对象实例变量的值
    id object_getIvar(id obj, Ivar ivar);
    
    // 设置对象实例变量的值
    void object_setIvar(id obj, Ivar ivar, id value);
    void object_setIvarWithStrongDefault(id obj, Ivar ivar, id value);
    
    // 修改类实例中实例变量的值
    Ivar object_setInstanceVariableWithStrongDefault(id obj, const char *name
    Ivar object_setInstanceVariable(id obj, const char *name, void *value);, void *value);
    
    // 获取指定名称的类,指定类名不存在会调用类回调处理
    Class objc_getClass(const char *name);
    // 返回指定的元类
    Class objc_getMetaClass(const char *name);
    // 返回指定的类
    Class objc_lookUpClass(const char *name)
    Class objc_getRequiredClass(const char *name);
    
    // 返回已注册的类定义的列表
    int objc_getClassList(Class *buffer, int bufferCount);
    // 创建并返回一个指向所有已注册类的列表指针
    Class *objc_copyClassList(unsigned int *outCount);
    
    // 返回类名
    const char *class_getName(Class cls) 
    
    // 是否是元类
    BOOL class_isMetaClass(Class cls);
    
    // 返回类的父类
    Class class_getSuperclass(Class cls);
    
    // 给类指定一个父类,并返回旧的父类
    Class class_setSuperclass(Class cls, Class newSuper);
    
    // 返回类的版本号
    OBJC_EXPORT int class_getVersion(Class cls);
    // 设置类版本号
    void class_setVersion(Class cls, int version);
    // 返回实例类的大小
    size_t class_getInstanceSize(Class cls);
    // 返回类中指定名称实例变量的信息
    Ivar class_getInstanceVariable(Class cls, const char *name);
    
    // 返回类中指定名称实例成员变量的信息
    Ivar class_getInstanceVariable(Class cls, const char *name);
    // 返回类指定名称变量的信息
    Ivar class_getClassVariable(Class cls, const char *name);
    
    // 返回整个成员变量列表
    Ivar *class_copyIvarList(Class cls, unsigned int *outCount);
    
    // 返回类中指定实例方法
    Method class_getInstanceMethod(Class cls, SEL name);
    // 返回类中指定的类方法
    Method class_getClassMethod(Class cls, SEL name);
    // 返回类中所有方法的列表
    Method *class_copyMethodList(Class cls, unsigned int *outCount);
    // 返回类方法的入口指针
    IMP class_getMethodImplementation(Class cls, SEL name);
    // 返回类方法实现的指针
    IMP class_getMethodImplementation_stret(Class cls, SEL name);
    /* An opaque type that represents a method in a class definition.
       Method是objc_method结构体类型指针
       objc_method结构体,包含了方法方法的名称,参数类型以及方法实现的入口指针(IMP)
    */ 
    typedef struct objc_method *Method;
    struct objc_method {
        SEL method_name                                 
        char * method_types                           
        IMP  method_imp                                  
    }   
    #if !OBJC_OLD_DISPATCH_PROTOTYPES
    typedef void (*IMP)(void /* id, SEL, ... */ ); 
    #else
    typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
    #endif
    
    // 类的实例是否响应指定的方法
    BOOL class_respondsToSelector(Class cls, SEL sel);
    
    // 返回类是否实现指定的协议
    BOOL class_conformsToProtocol(Class cls, Protocol *protocol);
    // 返回这个类所遵循的协议
    Protocol ** class_copyProtocolList(Class cls, unsigned int *outCount);
    
    // 返回类中指定名称的属性
    objc_property_t class_getProperty(Class cls, const char * name)
    // 返回类中声明的属性
    objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
    

    注意:class_copyPropertyList 和 class_copyIvarList 是不同的,前者获取的只是类中声明的属性变量,后者则是获取类中的实例变量

    @interface Person : NSObject
    {
        NSString *_name;
    }
    @property (nonatomic, assign) int sex;
    @property (nonatomic, assign) int age;
    @property (nonatomic, copy) NSString *tele;
    @end
    ---------------------------------------------------------------------------------------------
    - (void)viewDidLoad {
        [super viewDidLoad];
        uint count = 0;
        Ivar *ivarList = class_copyIvarList(objc_getClass("Person"), &count);
        for (int i = 0; i < count; i++) {
            NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
            NSLog(@"ivarName:%@",ivarName);
        }
        NSLog(@"---------------------------");
        uint count2= 0;
        objc_property_t *properties = class_copyPropertyList(objc_getClass("Person"), &count2);
    
        for (int i = 0; i < count2; i++) {
            NSString *propertyName = [NSString stringWithUTF8String:property_getName(properties[i])];
            NSLog(@"propertyName:%@",propertyName);
        }
    --------------------------------------console------------------------------------------------
    [1037:59125] ivarName:_name
    [1037:59125] ivarName:_sex
    [1037:59125] ivarName:_age
    [1037:59125] ivarName:_tele
     ---------------------------
    [1037:59125] propertyName:sex
    [1037:59125] propertyName:age
    [1037:59125] propertyName:tele
    
    // 获取类中强引用成员变量的布局
    const uint8_t *class_getIvarLayout(Class cls);
    // 设置变量布局
    void class_setIvarLayout(Class cls, const uint8_t *layout);
    // 获取类中弱引用成员变量的布局
    uint8_t *class_getWeakIvarLayout(Class cls);
    // 设置弱属性的变量布局
    void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
    

    ivar 的修饰信息在Class 的 Ivar Layout 中,具体看objc-runtime-new.hOC Class Ivar Layout 探索

    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;
    #ifdef __LP64__
        uint32_t reserved;
    #endif
        const uint8_t * ivarLayout; // 存储 strong 的 ivar
        const char * name;
        method_list_t * baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars;
    
        const uint8_t * weakIvarLayout; // 存储 weak 的 ivar
        property_list_t *baseProperties;
    
        method_list_t *baseMethods() const {
            return baseMethodList;
        }
    };
    
    // 为类添加新的方法
    BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) 
    // 方法存在时替代方法的实现,方法不存在时相当于class_addMethod
    IMP class_replaceMethod(Class cls, SEL name, IMP imp,  const char * types) 
    
    // 为类添加实例变量
    class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types) 
    // 为类添加新的协议
    class_addProtocol(Class cls, Protocol *protocol) ;
    // 添加属性
    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);
    
    // 通过CoreFoundation's自由连接。不能自己调用此方法
    Class objc_getFutureClass(const char *name);
    // 创建类实例
    id class_createInstance(Class cls, size_t extraBytes);
    // 在指定位置创建类实例
    id objc_constructInstance(Class cls, void *bytes);
    // 在不释放内存的情况下销毁类的实例,并删除此实例可能具有的任何关联引用。
    void *objc_destructInstance(id obj) 
    
    // 创建新的类
    Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
    // 注册由objc_allocateClassPair创建的类
    void objc_registerClassPair(Class cls) 
    

    以上两个函数一起创建一个新的类
    例如创建一个新的类Person,继承与NSObject:

    Class newCls = objc_allocateClassPair([NSObject class], "Person", 0);
    objc_registerClassPair(newCls);
    
    // 用于KVO观察者模式。 不能自己调用此方法
    Class objc_duplicateClass(Class original, const char * name, size_t extraBytes)
    // 销毁一个类及其相关联的类
    void objc_disposeClassPair(Class cls);
    
    // 返回方法的名称
    SEL method_getName(Method m);
    // 返回一个函数指针
    IMP method_getImplementation(Method m)
    
    上面这两个方法是不一样。
    前者:返回的SEL是一个objc_selector结构体类型指针:
    /// An opaque type that represents a method selector.
    typedef struct objc_selector *SEL;
    
    Mac OSX仅仅将SEL映射为C字符串所以相同的方法名具有相同的SEL编号,即使它们属于不同的类
    
    后者:返回的IMP本质上是一个函数指针的别名,直接指向函数在内存中的入口实现地址,而无需通过消息传递定位
    #if !OBJC_OLD_DISPATCH_PROTOTYPES
    typedef void (*IMP)(void /* id, SEL, ... */ ); 
    #else
    typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
    #endif
    
    // 返回方法接收参数的个数
    注意所有函数都有两个隐藏的参数SEL和_cmd,所以参数个数会多+2
    unsigned int method_getNumberOfArguments(Method m);
    // 返回描述方法返回类型的字符串
    char *method_copyReturnType(Method m)
    // 返回描述方法单个参数类型的字符串
    char *method_copyArgumentType(Method m, unsigned int index)
    // 通过引用返回描述方法的返回类型
    void method_getReturnType(Method m, char *dst, size_t dst_len) 
    // 通过引用返回描述方法的单个参数类型
    void method_getArgumentType(Method m, unsigned int index, char *dst, size_t dst_len);
    // 返回指定方法的结构描述
    struct objc_method_description *method_getDescription(Method m);
    
    struct objc_method_description {
        SEL name;               方法名
        char *types;          参数类型
    };
    

    具体参考:Type Encodings

    // 设置方法的入口实现地址
    IMP method_setImplementation(Method m, IMP imp);
    // 交换两个方法的实现入口地址
    void method_exchangeImplementations(Method m1, Method m2);
    

    ivar

    // 返回实例变量的名称
    const char *ivar_getName(Ivar v);
    // 返回实例变量类型字符串
    const char *ivar_getTypeEncoding(Ivar v);
    // 返回实例变量的偏移量
    ptrdiff_t ivar_getOffset(Ivar v);
    

    property

    // 返回属性名称
    const char *property_getName(objc_property_t property);
    // 返回属性的属性字符串
    const char *property_getAttributes(objc_property_t property);
    // 返回属性的属性数组
    objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount);
    // 返回指定属性名称的属性的值
    char *property_copyAttributeValue(objc_property_t property, const char *attributeName);
    

    protocol

    // 返回指定名称的协议
    Protocol *objc_getProtocol(const char *name);
    // 返回runtime已知的所有协议的数组
    Protocol * __unsafe_unretained *objc_copyProtocolList(unsigned int *outCount);
    // 判断一个协议是否遵循了另一个协议
    BOOL protocol_conformsToProtocol(Protocol *proto, Protocol *other);
    // 判断两个协议是否相等
    BOOL protocol_isEqual(Protocol *proto, Protocol *other);
    // 返回协议的名称
    const char *protocol_getName(Protocol *p);
    // 获取协议中指定方法的方法描述
    struct objc_method_description protocol_getMethodDescription ( Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod );
    // 获取协议中指定条件的方法的方法描述数组
    struct objc_method_description * protocol_copyMethodDescriptionList ( Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount );
    // 获取协议的指定属性
    objc_property_t protocol_getProperty ( Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty );
    // 获取协议中的属性列表
    objc_property_t * protocol_copyPropertyList ( Protocol *proto, unsigned int *outCount );
    // 返回协议中声明的属性列表
    objc_property_t *protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount, BOOL isRequiredProperty, BOOL isInstanceProperty)
    // 获取协议遵循的协议
    Protocol ** protocol_copyProtocolList ( Protocol *proto, unsigned int *outCount );
    // 创建新的协议实例
    Protocol * objc_allocateProtocol ( const char *name );
    // 在运行时中注册新创建的协议
    void objc_registerProtocol ( Protocol *proto );
    // 向协议中添加方法,必须在协议未注册之前
    void protocol_addMethodDescription ( Protocol *proto, SEL name, const char *types, BOOL isRequiredMethod, BOOL isInstanceMethod );
    //添加一个已注册的协议到未注册的协议中
    void protocol_addProtocol ( Protocol *proto, Protocol *addition );
    // 为协议添加属性,必须在协议注册之前
    void protocol_addProperty ( Protocol *proto, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount, BOOL isRequiredProperty, BOOL isInstanceProperty );
    
    // 返回所有加载的Objective-C框架和动态库的名称
    const char **objc_copyImageNames(unsigned int *outCount) 
    // 返回一个类所在的动态库名称
    const char *class_getImageName(Class cls);
    // 返回库中所有类的名称
    const char **objc_copyClassNamesForImage(const char *image,unsigned int *outCount);
    
    // 返回指定sel的方法的名称
    const char *sel_getName(SEL sel);
    // 使用OC运行时系统注册一个方法,将方法名映射到选择器SEL并返回SEL值
    SEL sel_registerName(const char *str);
    // 判断两个sel是否相同
    BOOL sel_isEqual(SEL lhs, SEL rhs);
    
    // 在每次迭代中检测到突变时,编译器插入此函数。 它在变异发生时被调用,并且如果设置了enumerationMutationHandler,则会执行。 如果未设置处理程序,则会发生致命错误。
    void objc_enumerationMutation(id obj) 
    // 设置当前突变的处理程序
    OBJC_EXPORT void objc_setEnumerationMutationHandler(void (*handler)(id));
    // 设置objc_msgForward调用的函数。
    void objc_setForwardHandler(void *fwd, void *fwd_stret) 
    
    // 创建一个当调用此方法时调用指定块的函数指针
     IMP imp_implementationWithBlock(id block);
    // 返回与使用imp_implementationWithBlock创建的IMP关联的块
    id imp_getBlock(IMP anImp);
    // 移除与使用imp_implementationWithBlock创建的IMP相关联的块的关联
    BOOL imp_removeBlock(IMP anImp)
    
    // 加载弱指针引用的对象并返回它
    id objc_loadWeak(id *location);
    // 存储_weak变量的新值
    id objc_storeWeak(id *location, id obj);
    
    // 设置对象对应key和和关联策略的关联值
    void objc_setAssociatedObject(id object, const void *key,  id value, objc_AssociationPolicy policy)
    // 获取对象给定key的关联值
    OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key);
    // 移除对象的所有关联
    void objc_removeAssociatedObjects(id object);
    

    相关文章

      网友评论

          本文标题:runtime概述

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