第11条说过:OC对象收到消息后,调用何种方法需要在运行期才能解析出来,所以给定的选择器名称相对应的方法,可以在运行期改变。不需要源代码和继承子类来覆写。新功能将在本类所有的实例中生效,这个方法叫“方法调配”(method swizzling)。
类的方法列表会把选择器的名称映射到相关方法的实现之上,使“动态消息派发系统”能够根据选择器的名称找到应该调用的方法。方法均以函数指针的形式来表示,这种指针叫做IMP。
id (*IMP)(id, SEL, ...)
开发者可以向类的选择器映射表中新增方法,也可以改变选择器所对应的方法实现,还可以交换两个选择器所映射的指针。
NSString类的选择器映射表.jpg NSString类修改后的选择器映射表.jpg
交换方法实现:
void method_exchangeImplementations(Method m1, Method m2)
参数:表示待交换的两个方法实现
获取方法实现:
Method class_getInstanceMethod(Class cls, SEL name)
参数:类,相关方法
互换两个已经写好的方法实现:
// 示例:
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString class], @selector(uppercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
NSString *string = @"This is the Stirng";
NSString *lowercaseString = [string lowercaseString];
NSLog(@"lowercaseString: %@",lowercaseString);
NSString *uppercaseString = [string uppercaseString];
NSLog(@"uppercaseString: %@",uppercaseString);
输出:
2018-08-18 23:11:38.549956+0800 Demo[12577:491276] lowercaseString: THIS IS THE STIRNG
2018-08-18 23:11:38.550262+0800 Demo[12577:491276] uppercaseString: this is the stirng
说明:
交换NSString类的lowercaseString与uppercaseString实现。
为既有方法实现新增新功能:
// 新建NSString类分类,头文件
#import <Foundation/Foundation.h>
@interface NSString (EOCMyAdditions)
- (NSString *)eoc_myLowercaseString;
@end
// 实现文件
#import "NSString+EOCMyAdditions.h"
@implementation NSString (EOCMyAdditions)
- (NSString *)eoc_myLowercaseString
{
NSString *lowercase = [self eoc_myLowercaseString];
NSLog(@"%@ => %@",self, lowercase);
return lowercase;
}
@end
// 使用
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString class], @selector(eoc_myLowercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
NSString *string = @"This is the Stirng";
NSString *lowercaseString = [string lowercaseString];
输出:
2018-08-18 23:17:24.038765+0800 Demo[12721:496759] This is the Stirng => this is the stirng
这样可以为“完全不知道具体实现”的黑盒方法增加日志记录功能。
一般,只有在调试程序的时候才需要在运行期修改方法实现,不宜滥用。
网友评论