前言:

最初对于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. Linux基础-目录结构

    /:根目录 /bin:存放可执行程序(二进制文件) /etc:存放系统或者用户安装的软件所用的一些配置文件 /lib:操作系统运行时候使用的一些基本动态库 /media:自动挂载外设,会将外设挂载到该 ...

  2. iOS Core Animation之CALayer心得

    使用CALayer的mask实现注水动画效果 Core Animation一直是iOS比较有意思的一个主题,使用Core Animation可以实现非常平滑的炫酷动画.Core animtion的AP ...

  3. ASP.NET ZERO 学习 HangFire的使用二

    之前在ABP配置好了HangFire环境之后,那么如何才能添加Job到HangFire中让其执行呢 这就需要参考ABP的Background Jobs and Workers, 参考路径:http:/ ...

  4. 第二章 centos安装maven

    一.官网下载 apache-maven-3.3.9-bin.tar.gz 注意:需要jdk1.7及以上 二.上传 scp apache-maven-3.3.9-bin.tar.gz root@10.2 ...

  5. html只给自己

    //另外一个 height:400px; weight:400px; border-top-left-radius: 10px; border-top-right-radius: 10px; bord ...

  6. RedHat 6.7 Enterprise x64环境下使用RHCS部署Oracle 11g R2双机HA

    环境 软硬件环境 硬件环境: 浪潮英信服务器NF570M3两台,华为OceanStor 18500存储一台,以太网交换机两台,光纤交换机两台. 软件环境: 操作系统:Redhat Enterprise ...

  7. 打造 html5 文件上传组件,实现进度显示及拖拽上传,支持秒传+分片上传+断点续传,兼容IE6+及其它标准浏览器

    老早就注册了博客园帐号,昨天才发现,连博客都没开,Github也是一样,深觉惭愧,赶紧潜个水压压惊`(*∩_∩*)′ 言归正传.大概许多人都会用到文件上传的功能,上传的库貌似也不少,比如(jQuery ...

  8. VBA常用函数

    字符串相关: ①截取字符串: 从字符串左侧开始:Left(string,length) 从字符串右侧开始:Right(string,length) 从字符串中间开始:mid(string,start, ...

  9. Masonry记录——iOS适配

    Masonry是iOS适配的第三方库,比较好用的一个,本人用的也不多,简单了解一些常用的方法,自己学习中,记录下来共勉. Masonry下载地址:https://github.com/SnapKit/ ...

  10. Linq To Nhibernate 性能优化(入门级)

    最近都是在用Nhibernate和数据库打交道,说实话的,我觉得Nhibernate比Ado.Net更好用,但是在对于一些复杂的查询Nhibernate还是比不上Ado.Net.废话不多说了,下面讲讲 ...