最后更新:2017-06-21

一、先说结论

void swizzleMethod(Class cls, SEL originalSelector, SEL swizzledSelector)
{
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); BOOL didAddMethod =
class_addMethod(cls,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod)); if (didAddMethod) {
class_replaceMethod(cls,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}

二、代码分析

2.1 class_getInstanceMethod()

获取某个类实例的方法, 如果该类实例没有此方法, 则返回NULL

Method swizzleMethod = class_getInstanceMethod([Person class], @selector(run));
if (swizzleMethod == NULL) {
NSLog(@"NULL");
}

参数解释

class_getInstanceMethod(Class cls, SEL name)

cls: 获取方法的类

name: 方法的名称

2.2 class_addMethod()

参数解释

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

cls: 获取方法的类

name: 添加的方法方法的名称

imp: 方法的实现,也就一个指向方法的指针

const char *types: 定义了返回值类型和参数类型的字符串(下面会提到)

返回值

YES: 增加方法成功

NO: 增加方法失败,例如 (如果目标类(Person) 实现了该方法,那么会返回 NO)

注意点

  • class_addMethod 能够覆盖父类的实现的;

    如果目标类有实现了该方法,class_addMethod就会失败

class_addMethod will add an override of a superclass's implementation

  • 处理警告问题

    参考: https://stackoverflow.com/questions/6224976/how-to-get-rid-of-the-undeclared-selector-warning

    void sayHello(id self, SEL _cmd, NSString *word)
    {
    NSLog(@"%@", word);
    } - (void)viewDidLoad {
    [super viewDidLoad]; #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wundeclared-selector"
    class_addMethod([Person class], @selector(resolveThisMethodDynamically:), (IMP)sayHello, "v@:@");
    Person *p = [[Person alloc] init];
    [p performSelector:@selector(resolveThisMethodDynamically:) withObject:@"hello"];
    #pragma clang diagnostic pop }
  • 需要动态调用,因为通过运行时添加的方法,直接调用 编译不过的

    正确做法:
    [p performSelector:@selector(resolveThisMethodDynamically:) withObject:@"hello"]; 错误做法,编译不过
    [p resolveThisMethodDynamically:@"hello"];
  • imp 默认自带两个参数, id类型 以及 SEL 类型

    void sayHello(id self, SEL _cmd, ...)

2.3 参数 const char *types 解释

v 表示的是void 类型

i 表示整数类型

@ 表示一个对象

: 表示一个方法

v@: 表示的是返回值类型是void, 一个参数是对象(id self),另一个参数为方法 (SEL _cmd)

v@

iOS-Swizzle的更多相关文章

  1. IOS Swizzle(hook)

    /////////////////////////////////////////////////////////////////////////////////////////////////// ...

  2. IOS Runtime的用法

    什么是runtime? 1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型.C语言函数)2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的* ...

  3. Objective-C:运行时runtime

    1.是否可以把比较耗时的操作放在通知中心中?   通知在哪一个线程发的,那么对通知事件的处理就在同一个线程中进行; 如果在异步线程发的通知,那么可以执行比较耗时的操作: 如果在主线程发的通知,那么就不 ...

  4. ios runtime swizzle

    ios runtime swizzle @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class orig ...

  5. Method Swizzle黑魔法,修改 ios 系统类库方法 SEL IMP

    Method Swizzle黑魔法,修改 ios 系统类库方法   版权声明:本文为博主原创文章,未经博主允许不得转载. 一般来说,系统提供的方法已经足够开发了,但是有的时候有些需求用普通方法不好做. ...

  6. 开源 iOS 项目分类索引大全 - 待整理

    开源 iOS 项目分类索引大全 GitHub 上大概600个开源 iOS 项目的分类和介绍,对于你挑选和使用开源项目应该有帮助 系统基础库 Category/Util sstoolkit 一套Cate ...

  7. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  8. IOS开发基础知识--碎片35

    1:iOS视图控制对象生命周期 init-初始化程序 viewDidLoad-加载视图 viewWillAppear-UIViewController对象的视图即将加入窗口时调用: viewDidAp ...

  9. 【原】iOS动态性(三) Method Swizzling以及AOP编程:在运行时进行代码注入

    概述 今天我们主要讨论iOS runtime中的一种黑色技术,称为Method Swizzling.字面上理解Method Swizzling可能比较晦涩难懂,毕竟不是中文,不过你可以理解为“移花接木 ...

  10. iOS Run_time

    Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给他人一些启发,三为 希望得到 ...

随机推荐

  1. Grafana设置匿名登录

    将配置文件中的auth.anonymous的enabled设置为true就可以匿名登录,不用输入用户名和密码 #################################### Anonymou ...

  2. 使用 java.util.Properties 读取配置文件中的参数

    配置文件格式 如下的配置参数格式都支持: Key = ValueKey = Key:ValueKey :Value 用法 getProperty方法的返回值是String类型. //读取配置文件 Fi ...

  3. UrlConnection发送http请求 中文乱码解决

    中文乱码 DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream()); //dos.writeBytes(jsonD ...

  4. MySQL-快速入门(6)连接查询、子查询、正则表达式查询、数据的插入删除更新

    1.内连接查询:inner join ... on 只有满足条件的记录才能够出现在结果关系中,即完全相等.自连接查询是一种特殊的内连接查询. 2.外连接查询: 1>左外连接 / 左连接:返回包括 ...

  5. 循环Gray码的生成(非递归)

    #!/usr/bin/env python #coding:utf-8 import sys def gray_code(n): if n < 1: return [] n += 1 array ...

  6. 极*Java速成教程 - (8)

    Java高级特性 注解 注解可以在代码之外添加更多的信息,更加完整地描述程序,帮助编译器进行工作,或者实现某些特定的Java代码之外的功能. 注解可以简化某些重复的流程,自动化那些过程. 注解的使用 ...

  7. 【PDF】手写字与识别字重叠

    [PDF]手写字与识别字重叠 前言 同学平时上课用iPad记笔记,考试之前导出为PDF发给我后,我用PDF打开,发现可以直接Ctrl+F搜索一些词语.一直不知道是怎么做到的,毕竟里面的字都是手写的,不 ...

  8. 区间动态规划 矩阵连乘 Medium

    The multiplication puzzle is played with a row of cards, each containing a single positive integer. ...

  9. PCIeのType0与Type1型配置请求与BAR(基地址寄存器)

    PCIe中存在两种配置空间Type0&type1,TYPE0对应非桥设备(Endpoint),Type1对应桥设备(Root和Switch端口中的P2P桥)因为Root每个端口总都含有一个P2 ...

  10. AFNetworking2.0源码解析<二>

    本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization.   AFURLRequestSerialization用于帮助构建NSURLReque ...