三 、动态添加方法

我们可以通过runtime动态地添加方法。那么到底啥叫动态添加方法呢?动态添加方法就是当我们程序运行时才知道我们应该调用哪个方法。我们首先需要了解这一点,当我们编写完一段代码后,我们点击run 的时候,编译器会先进行预编译、编译、链接、运行这几个步骤。C语言是再编译的时候就已经确定了函数的调用顺序,而OC在编译的时候,只是确定了哪个对象,发送什么消息,具体这个消息能不能找到对应的方法还不知道,只有在运行时,才能确定是否能够执行我们所期望的方法。我们以下面的代码为例:

  1. [person test_inPerson];
  2. // objc_msgSend(person, @selector(test_inPerson));上面的语句再编译后得到的就是这个函数。
  3.  
  4. // 通过编译我们能够知道三点:1、消息的接受者是person对象。2、需要执行名字为test_inPerson 的方法 3、这个方法不带参数

在上一篇博客中,我提到了SEL和IMP,但是由于写博客时已经太晚了,就没有认真地解释

如果想了解方法调用的过程,恐怕我们需要了解4个概念:(1)isa 指针。( 2)superclass 属性 。 (3)SEL 。  ( 4)IMP。

1) isa 指针:指向对象的类的指针。

2)superclass :指向父类。

3)SEL :选择器,是根据方法名字生成的ID, 每个selector其实是一个char*类型,记录对应IMP的位置。SEL列表本身是一个哈希存储的set集合,查找起来非常高效。

4) IMP:函数指针。

下面我们就来说一下方法调用的过程。

  1. /*
  2. 调用方法
  3. */
  4. [person test_inPerson];
  5.  
  6. /*
  7. 转换成消息
  8.  
  9. objc_msgSend(person, @selector(test_inPerson));上面的语句再编译后得到的就是这个函数。
  10. */
  11.  
  12. /*
  13. 1)检查 是否selector
  14.  
  15. 2)检查person 是否为空,如果为空的话就把selector也置为空,这样的话相当于什么也不做,当然也不报错
  16.  
  17. 3)根据SEL 查找IMP。首先从缓存中查找,看看缓存中是否存在SEL对应的IMP。如果存在则执行,否则继续下一步。
  18.  
  19. 4)根据SEL 和 isa 指针再IMP 列表中查找对应的IMP。如果找到则执行,否则执行下一步。
  20.  
  21. 5)根据superclass 和SEL 查找父类的IMP 如果找到则执行。否则继续执行这一步,直到NSObject 类。
  22.  
  23. 6)如果再NSObject类中仍然找不到方法,则会报错,找不到方法。
  24. */

了解了方法调用的过程,下面我们就来看看如何动态的添加方法。为了能够表达清楚,特在此敬上代码

  1. DZLPerson *person=[[DZLPerson alloc] init];
  2.  
  3. //发送消息想要执行名字为test0的方法,但是我们person类及其分类中并没有该方法的实现
  4. [person performSelector:@selector(test0)];
  1. #import "DZLPerson.h"
  2. #import <objc/runtime.h>
  3.  
  4. @implementation DZLPerson
  5.  
  6. /*
  7. 注意 这是函数 不是方法。函数是不能通过方法调用的。
  8. */
  9. void test0()
  10. {
  11. NSLog(@"test0 执行了");
  12. }
  13.  
  14. /*
  15. 如果找不到类方法则调用该方法,决定是否动态地添加方法
  16. */
  17. //+(BOOL)resolveClassMethod:(SEL)sel
  18. //{
  19. // return BOOL;
  20. //}
  21.  
  22. /*
  23. 如果找不到实例方法则调用该方法,决定是否动态地添加方法
  24. */
  25. +(BOOL)resolveInstanceMethod:(SEL)sel
  26. {
  27.  
  28. // 如果找不到的方法时test0 的话
  29. if ([NSStringFromSelector(sel) isEqualToString:@"test0"])
  30. {
  31.  
  32. //添加方法。其实就是将现有的函数实现(IMP) 和 SEL进行连接。
  33. class_addMethod(self,sel,test0,"v@:");
  34. }
  35.  
  36. return YES;
  37. }
  38.  
  39. @end

打印结果为

2015-04-13 22:43:06.406 runtime讲解[12452:693059] test0执行了


说明我们动态添加方法成功了。最后特别提示哦,如果函数和方法不是一回事,不要把他俩搞混了。方法是通过类或者对象调用的,而函数是可以直接调用执行的。

iOS 高级开发 runtime(三)的更多相关文章

  1. IOS高级开发 runtime(一)

    一. 简介 IOS 开发中灵活使用runtime 会提高我们的程序性能和开发速度.要想使用runtime,首先要引入系统的头文件. <span style="font-size:18p ...

  2. IOS 高级开发 runtime(二)

    二.移魂大法 使用runtime还可以交换两个函数.先贴上代码和执行结果. #import <Foundation/Foundation.h> @interface DZLPerson : ...

  3. (转发)IOS高级开发~Runtime(三)

    11.系统类的方法实现部分替换 - (void) methodExchange { Method m1 = class_getInstanceMethod([NSStringclass],@selec ...

  4. (转发)IOS高级开发~Runtime(四)

    用C代替OC: #import <objc/runtime.h> #import <objc/message.h> #import <stdio.h> extern ...

  5. (转发)IOS高级开发~Runtime(二)

    一些公用类: @interface ClassCustomClass :NSObject{ NSString *varTest1; NSString *varTest2; NSString *varT ...

  6. (转发)IOS高级开发~Runtime(一)

    IOS高级开发-Runtime(一) IOS高级开发-Runtime(二) IOS高级开发-Runtime(三) IOS高级开发-Runtime(四) 一些公用类: @interface Custom ...

  7. IOS高级开发之多线程(四)NSOperation

    1.什么是NSOperation,NSOperationQueue? NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作. ...

  8. ios高级开发之多线程(三)GCD技术

    GCD是基于C的API,它是libdispatch的的市场名称.而libdispatch作为Apple公司的一个库,为并发代码在多核硬件(跑IOS或者OS X)上执行提供有力支持. 那么我们为什么要用 ...

  9. IOS高级开发~Runtime(一)

    #import <Foundation/Foundation.h> @interface CustomClass : NSObject -(void)fun1; @end @interfa ...

随机推荐

  1. xp系统下网络打印机怎么设置

    亲测,可行 打印机共享可以有效节约办公资源,提高办公效率.可是还有很多朋友不知道怎么设置,我们这里讲一下网络打印机的设置方法. 1.我们点开桌面左下角的开始菜单,选择“打印机和传真” 2.我们右击某个 ...

  2. URL方式访问Hadoop的内容

    * 1.设置url支持hadoop,FsUrlStreamHandlerFactory      * 2.创建URL对象,指定访问的HDFS路径      * 3.openStream获取输入流对象, ...

  3. 利用stdin stdout stderr及POSIX-linux机制重定向写日志

    由open返回的文件描述符一定是该进程尚未使用的最小描述符.由于程序启动时自动打开文件描述符0.1.2,因此第一次调用open打开文件通常会返回描述符3,再调用open就会返回4.可以利用这一点在标准 ...

  4. WPF线程获取UI线程

    WPF中只能是UI线程才可以改变UI控件相关,当采用多线程工作时,可用以下代码获取 UI线程进行操作: App.Current.Dispatcher.Invoke((Action)delegate() ...

  5. PHP字符串操作汇总

    PHP开发中常用的字符串操作介绍 -- 简明现代魔法 PHP学习笔记之字符串的简单处理 - RuanJava的专栏 - 博客频道 - CSDN.NET PHP String 函数

  6. javascript闭包详解

    以前写过一篇关于javascript闭包的随笔,javascript闭包,但是写的不够详细,也没有体现出闭包的强大之处.故作此篇. 众所周知,javascript没有块级作用域,只有函数作用域.那就意 ...

  7. android游戏物理引擎开发——粒子系统(三)

    生病了,医院躺了几天,动了个小手术,动手术之后的几天在医院看了几本<大众软件>,又想到自己必须得买台台式机了,这破笔记本实在用不下去了,然后开始喜欢看些硬件的东西,等我熟悉了以后,写几个硬 ...

  8. Mybatis上路_06-使用Java自动生成

    目录[-] 1.编写Generator执行配置文件: 2.在MyEclipse中建空web项目: 3.编写并执行Java程序: 4.查看并修改生成的文件: 5.测试,使用生成的文件查询: 1)导入My ...

  9. 【转】在Windows下搭建React Native Android开发环境

    http://www.jianshu.com/p/2fdc4655ddf8 安装JDK 从Java官网下载JDK并安装.请注意选择x86还是x64版本. 推荐将JDK的bin目录加入系统PATH环境变 ...

  10. 【转】解决Cannot change version of project facet Dynamic web module to 2.5

    http://blog.csdn.net/steveguoshao/article/details/38414145 我们用Eclipse创建Maven结构的web项目的时候选择了Artifact I ...