zoukankan      html  css  js  c++  java
  • Runtime-总

    1.Runtime定义

    运行时,系统在运行时的一些机制,其中最主要的就是消息机制。对于C语言,函数的调用在编译时决定调用哪个函数。

    OC函数调用称为消息发送,属动态调用过程。在编译的是否并不能决定真正调用哪个函数(编译看指针,运行看实质,而C语言在编译阶段就会报错),只有真正运行的时候才会根据函数名称找到对应的函数来调用。

    2.基本功能点

    交换方法动态添加方法动态添加属性字典转模型

    更好理解类、对象、消息机制,以及运行期间代码动态交互

    3.常用的方法

    Person *p = [[Person alloc] init]; //alloc:分配内存空间 init 初始化对象(苹果不建议我们使用objc_msgSend,在build-setting 搜索 msg 打开

    导入 #import <objc/message.h>

     

    消息机制 (objc_msgSend  消息发送)

     

    #objc_getClass          获取类名

    #sel_registerName    注册方法编号

    Person * p = objc_msgSend(objc_getClass(“Person”),sel_registerName(“alloc”))

    #1.p = [p init];

    p = objc_msgSend(p,sel_registerName(“init”));

    #2.传参数 [p eatWith:@"汉堡!!"];

     objc_msgSend(p,sel_registerName(“eatWith:”),@“汉堡!!”);

    #3.给父类发送消息

    #objc_super                        结构体指针

    #objc_getSuperclass         获取父类指针

    HKPerson * p = [[HKPerson alloc] init];
    //定义hkSuper结构体
    struct objc_super hkSuper = {p,class_getSuperclass(objc_getClass(“HKPerson”))};
    //给父类发送消息
    objc_msgSend(&hkSuper, @selector(eatWith:),@“汉堡!!”);

     

    ②方法欺骗(MethodSwizzling 方法欺骗)

     

    (C语言的API。可以在OC编译运行阶段,动态的进行操作)

    1.SEL 方法的编号

    2.IMP 方法实现

    OC调用方法通过消息机制,给某个对象,发送方法编号信息,通过SEL可以找到对应的方法实现SEL和IMP是一一对应的

    面向切面编程-HOOK思想

    HOOK:钩子-修改原来的方法调用顺序,改变对应关系

    例子:NSURL不会检测是否为nil, 给系统的NSURL添加此功能

    HOOK: 在整个项目中,一旦你调用URLWithString ,就来到 HK_URLWithString (Runtime)

     #class_getClassMethod        获取类方法

     #class_getInstanceMethod  获取对象/实例方法

    实现步骤:

    //1->创建一个NSURL的类别
    +(instancetype)HK_URLWithString:(NSString *)URLString;
    //2->.m实现文件中
     #class_getClassMethod     获取类方法
     #class_getInstanceMethod  获取对象/实例方法
    #import "NSURL+hook.h"
    #import <objc/runtime.h>
    @implementation NSURL (hook)
    +(void)load {
        NSLog(@"Load..");
        //先执行 Load ,后执行Main函数
        //下钩子!! method_exchangeImplementations (A,B)  交换SEL 和IMP 的对应关系和指向
        /*
         SEL(目录) -- IMP(才是指针!)
         */
        //获取Method
        //class_getClassMethod     获取类方法
        //class_getInstanceMethod  获取对象/实例方法
        
        Method URLWithString = class_getClassMethod(self, @selector(URLWithString:));
        Method HK_URLWithString = class_getClassMethod(self, @selector(HK_URLWithString:));
        //method_exchangeImplementations
        //交换,下钩子
        method_exchangeImplementations(URLWithString, HK_URLWithString);
    }
    + (instancetype)HK_URLWithString:(NSString *)URLString {
        NSURL * url = [NSURL HK_URLWithString:URLString];//递归 发送 URLWithString 消息 又调用 HK_URLWithString
        if (url==nil) {
            NSLog(@"url 为 nil !!!");
        }
        return url;
    }

    ③动态添加方法(class_addMethod 动态添加方法)

     

    OC的方法调用,会传递两个隐式参数 (objc_msgSend(self, _cmd))id self 方法调用者; SEL _cmd方法编号

     我们可以使用resolveInstanceMethod和resolveClassMethod动态添加实例方法和类方法

    //如果该类接收到一个没有实现的实例方法,就会来到这里
    +(BOOL)resolveInstanceMethod:(SEL)sel {
        //NSLog(@"%@",NSStringFromSelector(sel));
        //动态添加一个方法!!
        /*
         1.class 哪个类
         2.SEL
         3.IMP 函数的指针
         4.返回值类型
         */
        class_addMethod(self, sel, (IMP)haha, "v@:@");
        return [super resolveInstanceMethod:sel];
    }
    void haha(id obj, SEL sel , NSString*objc) {
        //NSLog(@"吃到了%@",objc);
        //obj 调用者
        //sel 方法编号
        //objc 参数
        NSLog(@"%@--%@--%@",obj,NSStringFromSelector(sel),objc);//(null)--eat:--汉堡!!
        //objc_msgSend(p,@selector(eat:),@"汉堡");
    }
    void myMethodIMP(id self, SEL _cmd)//默认参数
    {
        // implementation ....
    }

    Runtime数据结构

    /*
    id : typedef struct objc_object *id;
    SEL : typedef struct objc_selector *SEL;
    Class : Class 也有一个 isa 指针,指向其所属的元类(meta)。
    ·super_class:指向其超类。
    ·name:是类名。
    ·version:是类的版本信息。
    ·info:是类的详情。
    ·instance_size:是该类的实例对象的大小。
    ·ivars:指向该类的成员变量列表。
    ·methodLists:指向该类的实例方法列表,它将方法选择器和方法实现地址联系起来。methodLists 是指向 ·objc_method_list 指针的指针,也就是说可以动态修改 *methodLists 的值来添加成员方法,这也是 Category 实现的原理,同样解释了 Category 不能添加属性的原因。
    ·cache:Runtime 系统会把被调用的方法存到 cache 中(理论上讲一个方法如果被调用,那么它有可能今后还会被调用),下次查找的时候效率更高。
    ·protocols:指向该类的协议列表(对象方法列表的扩展)。
    */

     动态添加属性

    #import <Foundation/Foundation.h>
    @interface NSObject (Property)
    // @property分类:只会生成get,set方法声明,不会生成实现,也不会生成下划线成员属性
    @property NSString *name;
    @end
    
    #import "NSObject+Property.h"
    #import <objc/message.h>
    
    @implementation NSObject (Property)
    
    //static NSString *_name;
    
    - (void)setName:(NSString *)name
    {
        // 让这个字符串与当前对象产生联系
        
    //    _name = name;
        // object:给哪个对象添加属性
        // key:属性名称
        // value:属性值
        // policy:保存策略
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (NSString *)name
    {
        return objc_getAssociatedObject(self, @"name");
    }
    
    @end

    Runtime常用API汇总

    objc_setAssociatedObject                              Sets an associated value for a given object using a given key and association policy      对象关联

    objc_getAssociatedObject                             Returns the value associated with a given object for a given key .                                      对象关联

    method_exchangeImplementations             Exchange the implementations of two methods .                                                                  方法调配(method swizzle)

    objc_getClassList                                            Obtains the list of registered class definitions                                                                         获取所有类的列表

    objc_getIvar                                                     Reads the value of an instance variable in an object .                                                            读取一个实例变量的值

    class_copyPropertyList                                  Describes the properties declared by a class .                                                                          获取属性列表(模型转字典)

    protocol_copyPropertyList                            Returns an array of the properties declared by a protocol.

    RunTime用法

    给Category添加属性

    Category中的属性只会生成set和get方法,不会生成成员变量

    重写setter和getter方法

    UIButton添加点击的时间间隔(class_replaceMethod、method_exchangeImplemetations)

    ③字典与模型互转

    ④自动归档

    ⑤动态方法解析(Dynamic Method Resolution)

    ⑥发送消息(objc_msgSend)

    ⑦消息转发(Message Forwarding)

    内存泄漏查找(MethodSwizzling替换ViewWillAppear,ViewDidDisappear)

    方法欺骗:钩子-修改原来的方法调用顺序,改变对应关系。一旦你调用URLWithString ,就来到 HK_URLWithString 

     

     

  • 相关阅读:
    Python find()方法
    Python expandtabs()方法
    RGB-D对红外热像仪和毫米波雷达标定
    ADAS虚拟车道边界生成
    3D惯导Lidar SLAM
    语义分割改进:通过视频传播和标签松弛
    YOLOv4:目标检测(windows和Linux下Darknet 版本)实施
    tensorflow-yolov4实施方法
    3D惯导Lidar仿真
    YOLOv4实用训练实践
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/Runtime_ALL.html
Copyright © 2011-2022 走看看