前言:

最初对于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. 查询AD账号的SID

    在非域控的计算机上可以查询所用AD用户的SID,不过现成的工具不能直接实现此目的,我们需要在这些计算机上安装RSAT(远程服务器管理工具),然后使用dsquery和dsget命令,来快速查询AD用户的 ...

  2. [ftp]Centos 创建 sftp 步骤

    来自:http://blog.csdn.net/xinxin19881112/article/details/46831311 1.创建sftp组 groupadd sftp 2.创建一个sftp用户 ...

  3. 关于activity的启动模式

    在Android中每个界面都是一个Activity ,界面的切换实际上是对不同Activity实例化的过程.而启动模式就决定Activity启动运行方式. 1.设置方式它是在主配置文件中,Activi ...

  4. HTTP、TCP、UDP以及SOCKET之间的区别/联系

    一.TCP/IP代表传输控制协议/网际协议,指的是一系列协组. 可分为四个层次:数据链路层.网络层.传输层和应用层. 在网络层:有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议. 在 ...

  5. C++基础-02

    函数重载 - 函数重载依据参数列表,而不依据返回类型 - 重载函数匹配规则: 精确匹配,不需要类型转换,但可以数组名到指针.函数名到指针和T到const T 提升匹配,bool.short.char到 ...

  6. 转js中this指向的简明解答

    JS中的this对象详解   JS中this关键字很常见,但是它似乎变幻莫测,让人抓狂.这篇文章就来揭示其中的奥秘. 借助阮一峰老师的话:它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用. ...

  7. [转] Oracle sql 查询突然变慢 -- 案例分析

    转自:http://jingyan.baidu.com/article/8275fc868ce57946a03cf692.html 一条sql突然执行变慢,耗时9秒,应用是不能改的,只能从数据库方面下 ...

  8. SVM学习笔记(二):什么是交叉验证

    交叉验证:拟合的好,同时预测也要准确 我们以K折交叉验证(k-folded cross validation)来说明它的具体步骤.{A1,A2,A3,A4,A5,A6,A7,A8,A9} 为了简化,取 ...

  9. MVC 构建图片/文件选择器 参考其它CMS功能

    实现结果,如下 点击选择图片,弹出一个iframe框 顶部默认图片根目录,依次下面是文件列表 底部是选择的文件地址,以及上传新的图片和文件 加载iframe 调用js方法 function initF ...

  10. LINUX 命令定期执行可执行文件

    linux命令将nodejs文件变成可执行文件 在linux中一般我们在运行node文件时用的命令为: node example.js 首先.删除文件后缀,在linux命令下添加可执行权限 mv ex ...