【Effective Objective-C 2.0 读书笔记】第十三条:用“方法调配技术“调试”黑盒方法“

第十三条:用“方法调配技术“调试”黑盒方法“

在消息解析时,与给定的选择子名称相对应的方法是不是也可以在运行时改变呢?

没错,就是这样。

若能善用此特性,则可发挥出巨大优势,因为我们既不需要源代码,也不需要通过继承子类来覆写方法就能改变这个类本身的功能。

这样一来,新功能将在本类的所有实例中生效,而不是仅限于覆写了相关方法的那些子类实例。

此方案经常成为“方法调配”(method swizzling)。

类的方法列表会把选择子的名称映射到相关的方法实现之上,使得“动态消息派发系统”能够据此找到应该调用的方法。

这些方法均以函数指针的形式来表示,这种指针叫做IMP,其原型如下:

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

类中的方法通过映射表把每个选择子都映射到不同的IMP上。

Objective-C运行期系统提供的几个方法都能够用来操作这张表。

开发者可以向其中增加选择子,也可以改变某选择子所对应的方法实现。

还可以交换两个选择子所映射到的指针。

无须修改类,或者编写子类,只要修改了“方法表”的布局,就会反映到程序中所有的实例上。

想交换方法实现,可用下列函数:

void method_exchangeImplementations(Method m1, Method m2)

此函数的两个参数表示待交换的两个方法实现,而方法实现则可以通过下列函数获得:

Method class_getInstanceMethod(Class aClass, SEL aSelector)

此函数根据给定的选择子从类中取出与之相关的方法。

例如:

Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));

Method swappedMethod = class_getInstanceMethod([NSString class], @selector(uppercaseString));

method_exchangeImplemetations(originalMethod, swappedMethod);

然而在实际应用中,像这样直接交换两个方法的实现的,意义并不大。

通常,我们新编写一个方法,在此方法中实现所需要的附加功能,与原有的方法交换。并调用原有实现。

通过此方法,开发者可以为那些“完全不知道其具体实现的”黑盒方法增加日志记录功能,这非常有利于程序的调试。

不能因为Objective-C有这个特性就一定要用它。若是滥用,反而会令代码变得不易读懂且难于维护。

【要点】

在运行期,可以向类中新增或替换选择子所对应的方法实现。

使用另一份实现来替换原有的方法实现,这道工序叫做“方法调配”,开发者通常用此技术向原有视线中添加新功能。

一般来说,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用。

你可能感兴趣的:(【Effective Objective-C 2.0 读书笔记】第十三条:用“方法调配技术“调试”黑盒方法“)