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 

     

     

  • 相关阅读:
    my first android test
    VVVVVVVVVV
    my first android test
    my first android test
    my first android test
    ini文件
    ZZZZ
    Standard Exception Classes in Python 1.5
    Python Module of the Week Python Module of the Week
    my first android test
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/Runtime_ALL.html
Copyright © 2011-2022 走看看