runtime记录

时间:2022-08-31 07:36:39

前言:

最初对于runtime的了解其实只停留在,知道这是一组C的方法,知道消息机制中会把方法调用转成objc_msgSend(theObject,@selector(objectMethod))。随后有一个具体的了解得益于一次尝试,使用runtime解决按钮连续点击限制;这个例子网上有一堆,就不再赘述,但是不得不说,runtime的基本使用都很巧妙的包含其中。也因此,我对runtime的理解更深入了;随后看了runtime的官方文档,知道了原来方法还有很多,但至此,依然不能灵活的运用。真正让我震撼的,是在敲MJExtension的时候runtime的使用灵活而随性,在我看来已经是出神入化(也可能我还没有理解的那么深刻),确实从中学习到很多。

需要知道的概念:

isa指针:

isa指针是每一个对象都会有的,指向这个对象所对应的类,在此要能够区分类和对象的不同;

SEL:

SEL相当于对方法的进一步封装,也可以当做是一个描述,每一个方法都有一个与之对应的SEL类型的数据,根据一个SEL可以找到方法地址,进而调用方法;

其类型定义为:typedef struct object_selector *SEL;

相关使用:SEL sel_1 = @selector(myMethodName:); //把一个方法名包装为一个SEL对象

NSString *str = NSStringFromSelector(sel_1); //得到一个SEL对象的名字;

[object performSelector:sel_1]; //performSelector中其实一直都在使用SEL对象;

Method:

Method是在方法链表中的存在形式,其中有一个SEL类型的selector和一个IMP类型的address,具体来说,就是一个对象的isa指针,指向对象所对应的类结构,而类结构中的参数包括父类、类名、版本信息、类信息、实例大小、实例参数链表、方法链表、方法缓存、协议链表;在方法链表中存储的就是Method;

struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指针 #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;

  相关方法:class_getInstanceMethod(Class cls, SEL name)  //返回SEL对应的Method对象

IMP:

IMP是指implementation的缩写,是指向方法地址的指针,每一个方法都有一个IMP地址,要注意,并不是只有属性才有地址,方法也有;

相关方法:method_getImplementation(Method m);  //runtime中的方法,返回该方法的IMP类型的方法实现地址;

[object methodForSelector:object_SEL];  //对象可以调用这个封装好的方法直接获得IMP指针;

        [class instanceMethodForSelector:object_SEL];  //上一个方法是实例方法,遍历实例的方法列表返回对应IMP,这个方法是一个类方法,区别在于遍历的是类的方法列表;其实具体实现是一样的;都是通过class_getInstanceMethod进行;

class cache:

分发表:

下面列出一些基本使用;

 
1、动态操作属性、方法;
 
     属性:
 
       objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
 
             object:表示给那个对象添加属性;
             key:属性对应的key值,再添加之后使用这个key来获取属性;
      value: 属性值;
             policy:策略枚举;
       理解:这个方法可以在你的复制方法中使用,赋值的时候直接关联一个新的属性,使用runtime写在方法内部,但是从表面来看抽象出的方法依然只完成了对于属性赋值,只不过内部的实现不再是 class.aaa = value 这样的语句而已;同时,如果在添加过属性关联之后,想要断开某个属性的关联,直接value传nil即可;
 
 
        objc_getAssociatedObject(id object, const void *key)
 
              object: 要取的是哪个对象的属性;
              key:属性对应的key值;
        理解:同上,和普通取值有所不同,但抽象之后依然只是取值,值得注意的是,返回值为id类型;
 
 
        objc_removeAssociatedObjects(id object)
        
              object:断开所有属性关联的对象;
        理解:其实从方法名也可以理解,这个方法用于断开所有关联的属性,会把对象恢复到原始状态;
 
         runtime属性的总结:其实动态的操作属性,就是在进行关联,关联本身就是runtime实现的一部分;我不需要修改类的相关定义,在运行过程中,基于关键字的方式给这个对象增加存储空间;
 
 
 
     方法:
 
        class_addMethod(Class cls,  SEL name, IMP imp, const char *types)
               
               cls:给哪个类添加方法;
               name: 原有方法的SEL,注意类型为SEL,你希望调用的方法名
               imp:新的方法的实现地址,当调用了这个name的方法时,你希望他执行哪一个方法地址;
               types:方法描述; 
        理解:向一个类增加一个方法实现,调用的时候其实还是老的方法名,但是执行的是新的方法实现过程,返回一个BOOL值,表示是否添加成功,其中最后一个参数表示方法的参数以及返回值描述;可使用method_getTypeEncoding(Method m)获得;其实这个方法包含了很多信息,有一个思考点,我们在代码中写了一个方法,但是内部是如何保存的呢?为什么就知道这个方法需要什么参数、什么样的返回值呢?其实这个方法已经比较隐含的表示了这个问题。
       
 

class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

        理解:替换方法,参数类型同上;
 
        method_exchangeImplementations(Method m1, Method m2)
        理解:直接交换两个方法的实现地址,即,当你调用方法m1是,其实对应的是m2的智行过程,反之依然,简单粗暴而有效;
 
    runtime方法小结:方法的使用一般都放在category里,另外OC中runtime会自动加载load方法,但在Swift中没有实现load方法,可以使用初始化方法;
 
 
 ------------------------------------ ------------------------------------ ------------------------------------ ------------------------------------ -----------------
 
    补充:class_addMethod这个方法里包含了一个逻辑点,如果原本类中没有这个方法,能够添加成功,返回YES,而已存在这个方法,返回NO;所以,需要添加的方法c是没有在cls这个类中定义过的,而imp需要指向一个已经实现过的方法,这时方法添加可以成功;但如果name是已经存在的方法,会得到NO的返回值;那么,如果原本类中存在方法a和方法b,我只是要交换两个方法的实现地址,即使用[object a]调用时,运行b的方法内容,使用[object b]调用时,运行a的方法内容,可以使用method_exchangeImplementations方法直接交换两个方法的实现地址;而如果想要使用类中没有定义的c方法来进行调用a的实现内容时,可以选择class_addMethod;class_replaceMethod则是直接使用已经存在的另外一个方法的实现地址,替换已有的name的实现地址,但是结果是,你调用a和b都是一样的实现内容;同样,这些方法的调用也不需要在本类内,另一个完全不相干的B类也可以对A类做方法操作; 
 
 
 
       转载请注明出处,有问题欢迎指出。
 
 

runtime记录的更多相关文章

  1. Redmine性能优化方案

    近来公司redmine服务器表现很糟糕,在16核,64GRAM的机器上,压测结果竟然只有每秒5~7个请求,部分页面一个都出不来. 以下是我对Redmine性能优化方案: redmine服务器性能问题排 ...

  2. [Rails] 从 Request 到 Response(1)

    本文翻译自:Rails from Request to Response 系列:个人选择了自己感兴趣的部分进行翻译,需要阅读原文的同学请戳前面的链接. 第一部分 导言(Introduction) 服务 ...

  3. freeMarker(九)——程序开发指南补充知识

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.变量.范围 本章介绍当模板在访问变量时发生了什么事情,还有变量是如 ...

  4. BigDecimal,注解

    BigDecimal 问题重现 今天在干活的途中,发现一个很坑爹的问题,让我来复现下问题: 从上游接口获得的余额,对于为0的,做了判断 BigDecimal a = new BigDecimal(ac ...

  5. WALT(Window Assisted Load Tracking)学习

    QCOM平台使用WALT(Window Assisted Load Tracking)作为CPU load tracking的方法:相对地,ARM使用的是PELT(Per-Entity Load Tr ...

  6. [踩坑记录] runtime error: load of null pointer of type 'const int' (leetcode)

    leetcode上面做题遇到的错误 原因: 在调用函数时,如果返回值如果是一个常量则没问题.如果返回值若为指针则可能会出现该错误,假如返回的指针地址指向函数内的局部变量,在函数退出时,该变量的存储空间 ...

  7. ASP.NET Core 1.0 开发记录

    官方资料: https://github.com/dotnet/core https://docs.microsoft.com/en-us/aspnet/core https://docs.micro ...

  8. Hadoop2.2.0安装过程记录

    1    安装环境1.1    客户端1.2    服务端1.3    安装准备    2    操作系统安装2.1.1    BIOS打开虚拟化支持2.1.2    关闭防火墙2.1.3    安装 ...

  9. Runtime应用防止按钮连续点击 (转)

    好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...

随机推荐

  1. a* products

    Experience of black-box testing on set-top-boxes/IP-connected devices, games consoles and tablets ht ...

  2. (六)责任链模式-C++实现

    使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止. 责任链模式是使用多个对象处理用户请求的成熟模式,它的关键 ...

  3. S3C2416裸机开发系列19_Fatfs播放录像wav音频文件

    S3C2416裸机开发系列19 Fatfs播放录像wav音频文件 国际象棋男孩    1048272975 多媒体资源,一般都是以文件的形式存储在固化存储器中.Fatfs所支持的fat32为windo ...

  4. 富文本编辑,xss攻击

    富文本编辑 KindEditor 在线HTML编辑器 http://kindeditor.net/doc.php 下载成功,解压放到项目中去 查看官方文档进行操作 xss攻击 XSS攻击全称跨站脚本攻 ...

  5. Ansible安装及OS规划

    Ansible安装  1.以管理用户mtnsadmin连接服务器后下载安装包(-O表示将下载的文件存放到指定的文件夹下,同时重命名下载的文件)     sudo wget -O /etc/yum.re ...

  6. go语言的安装、环境变量配置及简单使用

    go语言的安装.环境变量配置及简单使用 1.安装git并且配置在path中,默认就勾选了 下载地址https://git-scm.com/download/win 2.下载安装visualstudio ...

  7. [tomcat启动报错]registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped

    环境:一个tomcat ,一个工程配置了多数据源,在启动的时候报如下错误: SEVERE: The web application [/qdp-resource-job] registered the ...

  8. Spring事务管理实现方式之编程式事务与声明式事务详解(转)

    原文:https://blog.csdn.net/liaohaojian/article/details/70139151 编程式事务 编码方式实现事务管理(代码演示为JDBC事务管理) Spring ...

  9. xmapp+netbeans调试

    1.netbeans的设置 2.修改php.ini 如下: [XDebug]zend_extension = "D:\dev\xampp\php\ext\php_xdebug.dll&quo ...

  10. export,import ,export default的区别

    首先要知道export,import ,export default是什么 ES6模块主要有两个功能:export和importexport用于对外输出本模块(一个文件可以理解为一个模块)变量的接口i ...