最后更新: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. Ansible-playbook服务器初始化

    一.什么是Playbook playbook可以理解为ansible的shell脚本,它是一个编排工具,作用是使用编排出能够重复利用的ansible脚本,并并发处理多台服务器. 二.playbook使 ...

  2. mybatis使用map传递多参数报错:A query was run and no Result Maps were found for the Mapped Statement

    在使用mybatis进行多参数传递时,报错: A query was run and no Result Maps were found for the Mapped Statement 'xx.xx ...

  3. Tomcat 一台机器运行多个Tomcat

    转 https://www.cnblogs.com/andy1234/p/8866588.html 在一台Win10 PC 上面同时开启两个Tomcat系统为例. 1. 硬件环境 2. 到Tomcat ...

  4. P1754球迷购票问题

    这是一道动态规划题,其实也是个数论题. 有n人拿50,有n人拿100买票,必须让50元的人买,不然无法找零钱,问最多有几种方案可以每一次都买票成功.这个题首先令人想到搜索,但是随即发现dp是正解,于是 ...

  5. web 过滤器 Filter、 Spring 拦截器 interceptor

    1.过滤器(Filter)(在web.xml中注册过滤器) 首先说一下Filter的使用地方,我们在配置web.xml时,总会配置下面一段设置字符编码,不然会导致乱码问题: <filter> ...

  6. json.dumps、json.dump、json.loads、json.load的区别

    json 模块提供了一种很简单的方式来编码和解码JSON数据. 其中两个主要的函数是 json.dumps() 和 json.loads() 下面是如何将Python数据结构转换为json impor ...

  7. SSM获取前台参数的方式

    1.直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交.若"Content-Type"="application/ ...

  8. 001-supervisor

    supervisor 使用教程(转) 原文地址:https://word.gw1770df.cc/2016-08-04/linux/supervisor-%E4%BD%BF%E7%94%A8%E6%9 ...

  9. AT Regular 086

    C - Not so Diverse 略 D - Non-decreasing 先找绝对值最大的数 构造出全正(最大的数为正) 或者全负(最大的数为负) 然后前缀和(正)或者后缀和(负) 操作次数2n ...

  10. AtomicReference和AtomicStampedReference

    AtomicReference类提供了一个可以原子读写的对象引用变量. 原子意味着尝试更改相同AtomicReference的多个线程(例如,使用比较和交换操作)不会使AtomicReference最 ...