在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有就是方法交换

方法交换的原理:在OC中调用一个方法其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector方法的实现,达到和方法挂钩的目的。

每一个类都有一个方法列表,存放在selector的名字和方法实现的映射关系,imp有点像函数指针,指向具体的方法实现。

可以利用method_exchanggeimplementations来交换两个方法的imp

可以利用class_replaceMethod来替换方法的imp

可以利用method_setimplementation来直接设置某个方法的imp

归根结底方法交换就是偷换了selector的imp

Method Swizzling 实践

举个例子好了,就替换NSArray的objectAtIndex:方法吧,只需两个步骤。

第一步:自定义一个objectAtIndex:方法,方法名不能和系统的一样

#import <objc/runtime.h>
#import "NSArray+Swizzle.h"
@implementation NSArray (Swizzle)
-(id)ll_ObjectAtIndex:(NSUInteger)index{ if (index < [self count]) { return [self ll_ObjectAtIndex:index]; }else{ return nil; } }
乍一看,这不递归了么?别忘记这是我们准备调换IMP的selector,[self ll_ObjectAtIndex:index] 将会执行真的 [self objectAtIndex:index] 。 
第二步:调换IMP
+(void)initialize{

    static dispatch_once_t once;

    dispatch_once(&once, ^{

        Class class = NSClassFromString(@"__NSArrayI");

        [self swizzleMethods:class originalSelector:@selector(objectAtIndex:) swizzledSelector:@selector(ll_objectAtIndex:)];

    });

}

//方法交换的具体实现

+ (void)swizzleMethods:(Class)class originalSelector:(SEL)origSel swizzledSelector:(SEL)swizSel

{

    Method origMethod = class_getInstanceMethod(class, origSel);

    Method swizMethod = class_getInstanceMethod(class, swizSel);

    //class_addMethod will fail if original method already exists

    BOOL didAddMethod = class_addMethod(class, origSel, method_getImplementation(swizMethod), method_getTypeEncoding(swizMethod));

    if (didAddMethod) {

        class_replaceMethod(class, swizSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));

    } else {

        //origMethod and swizMethod already exist

        method_exchangeImplementations(origMethod, swizMethod);

    }

}

@end  
定义完毕新方法后,需要弄清楚什么时候实现与系统的方法交互?
既然是给系统的方法添加额外的功能,换句话说,我们以后在开发中都是使用自己定义的方法,取代系统的方法,所以,当程序一启动,就要求能使用自己定义的功能方法.说到这里:我们必须要弄明白一下两个方法 :
+(void)initialize(当类第一次被调用的时候就会调用该方法,整个程序运行中只会调用一次)
+ (void)load(当程序启动的时候就会调用该方法,换句话说,只要程序一启动就会调用load方法,整个程序运行中只会调用一次)
方法交换可以做什么呢
1、防止数组越界
2、统计页面的访问次数(通过交换viewdidload 或者 viewwillappear等方法)
当然还有很多其他的用途,这些只是较为常见的


												

Runtime之方法交换的更多相关文章

  1. runtime 实现方法交换 viewwillappear方法

    1.新建分类 #import "UIViewController+swizzling.h"#import <objc/runtime.h> @implementatio ...

  2. 我写的RunTime函数之一,为类的某个属性赋值以及方法交换

      1,为属性赋值 #import <UIKit/UIKit.h> @interface UIViewController (RunTime) - (BOOL)setPropertyVal ...

  3. Runtime 应用(一)拦截系统自带的方法交换实现

    动态的交换方法能够给项目中大量已经使用的方法 进行拦截增加操作 实践:利用运行时交换系统的ImageNamed:方法 应用背景 当系统需要适配ios7和ios8时可能会有显示不同图片的需求,但在老项目 ...

  4. 快速上手Runtime(三)之方法交换

    开发过程中,我们经常会用到系统类,而它提供的方法又不能完全满足我们开发的需要,那么在此时,我们需要为系统自带的方法扩展一些功能,而且还要保证原有的功能可正常使用.假设咱们现在有这么一个需求,我们在调用 ...

  5. runtime之方法的交换

    工作中没怎么用到runtime的东西,所以一直没怎么看,现在开始拿起来. runtime之方法的交换: 都知道OC中有category可以对已知类进行扩展,但是假如工程中需要修改某类的原方法,若用ca ...

  6. iOS 为何使用runtime方法交换多次后却能按照交换顺序依次执行代码逻辑?

    题目: 假设我们有一个ViewController, Category A(ViewController), Category B(ViewController), Category C(ViewCo ...

  7. Runtime之方法

    前两篇介绍了类与对象.成员变量&属性&关联对象的相关知识,本篇我们将开始讲解Runtime中最有意思的一部分内容:消息处理机制.我们从一个示例开始. 在OC中,我们使用下面这种方式来调 ...

  8. OC方法交换swizzle详细介绍——不再有盲点

    原文链接:https://www.cnblogs.com/mddblog/p/11105450.html 如果对方法交换已经比较熟悉,可以跳过整体介绍,直接看常见问题部分 整体介绍 方法交换是runt ...

  9. Java Runtime.availableProcessors()方法

    Java Runtime.availableProcessors()方法用法实例教程.   描述 java.lang.Runtime.availableProcessors() 方法返回到Java虚拟 ...

随机推荐

  1. 031、Java中偶数偶数的判断方法

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  2. flutter安装中的一些方法

    1.配置flutter环境变量 进入终端 vim ~/.bash_profile export ANDROID_HOME=~Library/Android/sdk export PATH=$PATH: ...

  3. PG、GP与MySQL的特点和区别

    参考 PostgreSQL数据库 介绍:PostgreSQL是一种运行在Unix和Linux操作系统(在NT平台借助Cygnus也可以运行)平台上的免费的开放源码的关系数据库.最早是由美国加州大学伯克 ...

  4. Ubuntu 终端命令速查表

    1.man: shell命令的说明指南 该命令代表manual,提供一个给定命令的说明指南. 用法:man <shell command> 用例:man ls 上述命令请求命令‘ls’的说 ...

  5. Codeforces Round #619 (Div. 2)

    A. Three Strings 题意:给三个长度相同的非空字符串abc,依次将c中的每个字符和a或者b中对应位置的字符进行交换,交换必须进行,问能否使得ab相同. 思路:对于每一个位置,如果三个字符 ...

  6. UVA - 10891 Game of Sum (区间dp)

    题意:AB两人分别拿一列n个数字,只能从左端或右端拿,不能同时从两端拿,可拿一个或多个,问在两人尽可能多拿的情况下,A最多比B多拿多少. 分析: 1.枚举先手拿的分界线,要么从左端拿,要么从右端拿,比 ...

  7. cf 762D. Maximum path

    天呢,好神奇的一个DP23333%%%%% 因为1.向左走1格的话相当于当前列和向左走列全选 2.想做走超过1的话可以有上下走替代.而且只能在相邻行向左. 全选的情况只能从第1行和第3行转移,相反全选 ...

  8. TensorFlow中的L2正则化函数:tf.nn.l2_loss()与tf.contrib.layers.l2_regularizerd()的用法与异同

    tf.nn.l2_loss()与tf.contrib.layers.l2_regularizerd()都是TensorFlow中的L2正则化函数,tf.contrib.layers.l2_regula ...

  9. 对plotTree的解释

    1.>>>a = 1/2/2   >>>a >>>0.25 2.def plotMidText(cntrPt,parentPt,txtString ...

  10. 爬虫(十七):Scrapy框架(四) 对接selenium爬取京东商品数据

    1. Scrapy对接Selenium Scrapy抓取页面的方式和requests库类似,都是直接模拟HTTP请求,而Scrapy也不能抓取JavaScript动态谊染的页面.在前面的博客中抓取Ja ...