(方法调配)Method Swizzling

一、概念

  方法调配:因为Objective-C是运行时语言,也就是说究竟会调用何种方法要在运行期才能解析出来。那么我们其实也可以在运行时改变选择子名称。这样我们既不需要查看到源代码,又没有必要去重写子类来覆写方法就能改变类本身的功能。这样一来新功能就会在类的所有实例中表现出来,而不仅限于那些重写子类的实例。这种方案就叫做“方法调配”(method swizzling)。

  IMP:类方法列表会把选择子的名称映射到方法的实现上,使得动态消息派发系统能够据次找到应该调用的方法,这些方法均以指针的形式来表示,这种指针叫做IMP。其原型如下:

id(* IMP)(id,SEL,.....)

  SEL:选择器用于表示一个方法在运行时的名字,一个方法的选择器是一个注册到(或映射到)Objective-C运行时中的C字符串,它是由编译器生成并在类加载的时候被运行时系统自动映射。

  一个类(Class)维护一张调度表(dispatch table)用于解析运行时发送的消息;调度表中的每个实体(entry)都是一个方法(Method),其中key值是一个唯一的名字——选择器(SEL),它对应到一个实现(IMP)——实际上就是指向标准C函数的指针。

二、方法调配的实现

首先看两张图片:


以上图2-3是NSString可以相应的选择子lowercaseString,uppercaseString,capitalizedString。每个选择子都映射到了不同的IMP。现在我们通过运行系统提供的方法来将选择子映射表改为2-4所示的映射表。

先简单说一下:我们没有重写子类或者其他,而是修改了方法的布局,这样就会反映到所有的NSString实例上。以下是一些基本的函数操作以及作用:

①、交换方法的实现

void method_exchangeImplementations(Method m1,Method m2)

此方法的参数是两个方法实现,方法实现可以通过以下函数获得:

Method class_getInstanceMethod(Class class,SEL aSelector)

次方法根据给定的选择从类中取出相应的方法。现在举个例子交换lowcaseString和uppercaseString:

Method originMethod = class_getInstanceMethod([NSString class],@selector(lowcaseString));
Method swipMethod = class_getInstanceMethod([NSString class],@selector(uppercaseString));

method_exchangeImplementations(originMethod,swipMethod);

此时如果我们调用NSString的lowcaseString那么实现的结果是uppercaseString的实现。(即如果调用小写转换则是大写转换)。

直接交换的意义不大,我们一般都会用在想重写一个类的方法,然后添加自己的东西,然后将这个方法和类现有的方法进行交换。

②、添加新的方法:

+ (IMP)swizzleSelector:(SEL)origSelector
 withIMP:(IMP)newIMP {
 Class class = [self class];
 Method origMethod = class_getInstanceMethod(class,
 origSelector);
 IMP origIMP = method_getImplementation(origMethod); 

 if(!class_addMethod(self, origSelector, newIMP,
 method_getTypeEncoding(origMethod)))
 {
 method_setImplementation(origMethod, newIMP);
 } 

 return origIMP;
} 


具体就不在介绍了。你懂的,,,,

三、总结:

1、在运行期间可以通过方法调配新增或者替换选择子对应方法的实现。

2、使用另一份实现来替换原有的实现,这道程序就叫做方法调配。

3、一定要注意使用,一般来说只有在调试程序的时候才去进行方法调配,很少有人在调试程序之外去直接改动某个类的功能。

四、结束语:

method swizzling就介绍这么多吧,希望能够帮助到大家。

时间: 2025-01-21 06:58:24

(方法调配)Method Swizzling的相关文章

Runtime Method Swizzling

原文出自:标哥的技术博客 前言 在我学习runtime的method swizzling特性之前,有很多同事或者朋友经常在我耳边说起swizzling特性,一个个在我面前说这个东西千万不能用,会引起很多问题的.但是,在我学习完这一节的知识后,我终于明白其所以然. 学习完swizzling特性后,我很喜欢她.她就像一把双刃剑,用好了可以带你飞,乱用则会反伤.但是,我更相信她的强大,更相信自己够能驾驭她!一起来学习吧! Method Swizzling 试想一下,苹果的源码是闭源的,我们只有类名和类

method swizzling-ios 用Method Swizzling修改字体出现问题了,求大神帮忙看一下,谢谢了,在线等

问题描述 ios 用Method Swizzling修改字体出现问题了,求大神帮忙看一下,谢谢了,在线等 buttonWithType:创建的按钮的字体怎么都改不了,myButtonWithType:这个方法就进不去. 我是新手,求大神帮帮忙看一下 ``@implementation UIButton (myFontBtn) +(void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class clas

ASP.NET MVC 5 - 验证编辑方法(Edit method)和编辑视图(Edit view)

原文:ASP.NET MVC 5 - 验证编辑方法(Edit method)和编辑视图(Edit view) 在本节中,您将验证电影控制器生成的编辑方法(Edit action methods)和视图.但是首先将修改点代码,使得发布日期属性(ReleaseDate)看上去更好.打开Models \ Movie.cs文件,并添加高亮行如下所示: using System; using System.ComponentModel.DataAnnotations; using System.Data.

java反射机制如何 得到当前方法的 method对象

问题描述 写了个获取调用方法的method对象的方法,但是无法区分重载方法publicstaticMethodgetCurrentMethod(){StackTraceElement[]yste=Thread.currentThread().getStackTrace();if(yste.length<2){returnnull;}/**getMethodName**/Stringstr="";for(inti=0;i<yste.length;i++){if(yste[i]

工厂模式之二 - 工厂方法(Factory Method)

工厂方法(Factory Method)模式又叫做多态性工厂(Polymorphic Factory). 简单工厂模式的优缺点 优点:将类的创建逻辑从客户端移入工厂类. 缺点:对开-闭原则支持不够,如果有新类加入,必须修改工厂类的逻辑.   工厂方法克服了简单工厂模式的缺点,引入了多态性.   工厂方法和简单工厂的区别: 简单工厂模式的核心是一个具体类,工厂方法模式的核心是一个抽象类.  下面我们来看一下工厂方法的具体实现,我们还是以画图程序为例子. 图形的代码结构和简单工厂类似,读者可以参看简

Java 设计模式之工厂方法(Factory Method)

类型: 对象创建型模式 意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类. Factory Method使一个类的实例化延迟到其子类. 适用性: 当一个类不知道它所必须创建的对象的类的时候. 当一个类希望由它的子类来指定它所创建的对象的时候. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候. 结构: 参与者: Product(Document) - 定义工厂方法所创建的对象的接口. • ConcreteProduct(MyDoc

OC 自动生成分类属性方法

分类属性方法自动生成编码全过程. 背景 分类,在 iOS 开发中,是常常需要用到的.在分类里添加属性也是常有的事,但分类中无法添加实例变量,编译器也无法为提供分类中属性的 getter 和 setter 方法了.一般而言,需要手动来实现这两个方法,如果只是用来存储变量的话,关联对象很容易做到这一点: @interface NSObject (db_sqlite) @property (nonatomic, assign) int db_rowid; @end @implementation NS

JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践

JAVA进阶之旅(二)--认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践 我们继续聊JAVA,这次比较有意思,那就是反射了 一.认识Class类 想要反射,你就必须要了解一个类--Class,我们知道,java程序中的各个java类都属于同一事物,我们通常用Classliability描述对吧,反射这个概念从JDK1.2就出来了,历史算是比较悠久了,这个Class可不是关键字哦,这个是一个类,他代表的是一类事物: 我们归根结底就

浅谈实例Page Method到静态Page Method的移植

最近被问及Page Method的问题比较多,主要还是如何从Atlas CTP中的非静态Page Method转向Beta或RC中的静态Page Method时所遇到的问题.现在我来谈一下在这方面的一些看法,也希望大家能和我一起探讨一下. 在当时,只要在Code Behind的Page类中添加一个实例方法,并且使用WebMethodAttribute进行标记即能使用,例如: [WebMethod] public string GetString(string split){ return thi