美文网首页
runtime基础知识

runtime基础知识

作者: zelo | 来源:发表于2017-09-07 09:24 被阅读32次

    我们都知道oc是动态语言,所谓的动态语言就是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上变化的语言。因为它可以在程序执行过程中对类或者变量等等做操作,而不是代码写完了,程序就定型了。

    runtime的所有知识基本都围绕两个中心(1)类的各个方面的动态配置(2)消息传递

    要动态配置类就需要知道类的本质是什么,我们可以从里面看到类的定义:

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

    isa和super_class

    不同的类中可以有相同的方法,同一个类中不可以有相同的方法,判断是不是同一个方法只和方法名有关系,和参数没关系。
    比如说:

    1

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{}
    

    的方法名为

    @selector(tableView:canEditRowAtIndexPath:)
    

    可见方法名里面并没有体现参数的位置,所以是否是同一个方法取决于方法名是否相同,和参数没关系。

    要找到方法首先要先确定是那个类。isa和super_class是找到实现函数的关键映射,决定找到存放在哪个类的方法实现。(isa用于自省确定所属类,super_class确定继承关系)。

    实例对象的isa指针指向类,类的isa指针指向其元类(metaClass)。对象就是一个含isa指针的结构体。类存储实例对象的方法列表,元类存储类的方法列表,元类也是类对象。

    当创建实例对象时,分配的内存包含一个objc_object数据结构,然后是类到父类直到根类NSObject的实例变量的数据。NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。

    向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表由super_class指针找到父类的方法列表直至根类NSObject中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。

    在正式学习runtime之前你需要知道的

    属性概念

    SEL:类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。

    IMP:一个函数指针,保存了方法的地址

    Method:方法的结构体,其中保存了方法的名字,实现和类型描述字符串

    //在runtime.h里面我们可以看到定义
    //Method 是一个方法结构体的指针
    typedef struct objc_method *Method;
    //方法的结构体包含了方法需要的信息
    struct objc_method {
      SEL method_name;
      char *method_types;//方法返回值,和各个参数类型等的字符串描述
      IMP method_imp;
    }   
    //根据函数获取函数的SEL
    @selector()
    //获取函数指针SEL的函数名字符串
    NSString *NSStringFromSelector(SEL aSelector);
    //根据函数名获取函数指针
    SEL NSSelectorFromString(NSString *aSelectorName);
    //获取类Class的字符串描述
    NSString *NSStringFromClass(Class aClass);
    //根据类的字符串描述获取类Class
    Class _Nullable NSClassFromString(NSString *aClassName);
    //获取协议的字符串描述(协议名字)
    NSString *NSStringFromProtocol(Protocol *proto)
    //根据协议名字获取协议对象
    Protocol * _Nullable NSProtocolFromString(NSString *namestr)
    

    下面会用到的编码值

    //下面对应的编码值可以在官方文档里面找到
    //编码值     含意
    //c     代表char类型
    //i     代表int类型
    //s     代表short类型
    //l     代表long类型,在64位处理器上也是按照32位处理
    //q     代表long long类型
    //C     代表unsigned char类型
    //I     代表unsigned int类型
    //S     代表unsigned short类型
    //L     代表unsigned long类型
    //Q     代表unsigned long long类型
    //f     代表float类型
    //d     代表double类型
    //B     代表C++中的bool或者C99中的_Bool
    //v     代表void类型
    //*     代表char *类型
    //@     代表对象类型
    //#     代表类对象 (Class)
    //:     代表方法selector (SEL)
    //[array type]     代表array
    //{name=type…}     代表结构体
    //(name=type…)     代表union
    //bnum     A bit field of num bits
    //^type     A pointer to type
    //?     An unknown type (among other things, this code is used for function pointers)
    
    //获取类名
    //入参:类Class
    //返回:类名char数组
    const char *class_getName(Class cls)
     
    //获取父类
    //入参:类Class
    //返回:类Class
    Class class_getSuperclass(Class cls)
     
    //获取实例大小(返回size_t)
    //入参:实例的类Class
    //返回:大小size_t
    //深究请看这篇文章http://www.jianshu.com/p/df6b252fbaae
    size_t class_getInstanceSize(Class cls)
     
    //获取类中指定名称实例成员变量的信息
    //入参:类Class,变量名
    //返回:变量信息Ivar
    //* 1.实例变量是指变量不是属性.例如某类有个属性为:username 那么它对应的实例变量为_username
    //* 2.这个方法可以获取属性的变量,也可以获取私有变量(这点很重要)
    //* 3.如果获取的变量为空,那么 ivar_getName和 ivar_getTypeEncoding 获取的值为空,那么[NSString stringWithUTF8String:ivar1Name] 执行崩溃
    Ivar class_getInstanceVariable(Class cls, const char *name)
     
    //类成员变量的信息
    //入参:类Class,变量名char数组
    //返回:Ivar
    //* 1.目前没有找到关于Objective-C中类变量的信息,一般认为Objective-C不支持类变量。注意,返回的列表不包含父类的成员变量和属性。
    Ivar class_getClassVariable(Class cls, const char *name)
     
    //获取指定的属性
    //入参:类Class,属性名char数组
    //返回:属性objc_property_t
    // *  1.属性不是变量,此方法只能获取属性
    // *  2.如果属性不存在那么返回的结构体为0(可以参考下面的判断)
    // *  3.属性不存在获取property_getName 和 property_getAttributes 会崩溃
    objc_property_t class_getProperty(Class cls, const char *name)
     
    //获取方法实现
    //入参:类Class,方法名SEL
    //返回:方法实现IMP
    IMP class_getMethodImplementation(Class cls, SEL name)
    //获取方法实现
    //入参:类Class,方法名SEL
    //返回:方法实现IMP
    IMP class_getMethodImplementation_stret(Class cls, SEL name)
     
    //获取类方法
    //入参:类Class,方法名SEL
    //返回:方法Method
    Method class_getClassMethod(Class cls, SEL name)
    

    企业级独立部署应用:知行办公http://zx.naton.cn
    【总监】十二春秋之,3483099@qq.com
    【Master】zelo,616701261@qq.com
    【运营】运维艄公,897221533@qq.com
    【产品设计】流浪猫,364994559@qq.com
    【体验设计】兜兜,2435632247@qq.com
    【iOS】淘码小工,492395860@qq.com;iMcG33K,imcg33k@gmail.com
    【Android】人猿居士,1059604515@qq.com;思路的顿悟,1217022114@qq.com
    【java】首席工程师MR_W,feixue300@qq.com
    【测试】土镜问道,847071279@qq.com
    【数据】喜乐多,42151960@qq.com
    【安全】保密,你懂的。

    相关文章

      网友评论

          本文标题:runtime基础知识

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