我们知道,OC是一门动态运行时语言。我们也知道,OC中的函数调用本质上其实是消息的发送:objc_MsgSend(someObject, @selector(methodName), parameters)
。所有要调用的函数,编译阶段是无法确定的,只有到运行的时候才能确定!正因为有此特性,所以在运行阶段,我们都还可以做很多事,而要把本来应该实现的方法A,偷偷换成方法B,便是其中的一种,这种技术叫做:Method Swizzling(方法交换)!
具体相关的概念就不再啰嗦了,网上都有很多了,可以自行google或者查阅《Effective Objective-C 2.0 编写高质量iOS与OS X 代码的52个有效方法》的第13条,介绍的都比较详细了。这里就总结一下相关的应用!
调试用
假如每次调用NSString的lowerCaseString方法时,不要每次都去NSLog,希望直接调用系统的方法时每次都可以输出log,那么这时候就可以用到该技术:
@interface NSString (XPPMyAdditions)
- (NSString *)xpp_myLowerCaseString;
@end
@implementation NSString (XPPMyAdditions)
- (NSString *)xpp_myLowerCaseString
{
NSString *LowerString = [self xpp_myLowerCaseString];
NSLog(@"%@->%@", self, LowerString);
return LowerString;
}
接下来做的就是把这个分类里面的方法和原生的方法交换一下:
void swizzling(){
Method originalMtd = class_getInstanceMethod([UIF class], @selector(xpp_myLowerCaseString));
Method swappedMtd = class_getInstanceMethod([NSString class], @selector(lowercaseString));
method_exchangeImplementations(originalMtd, swappedMtd);
}
那么在以后,直接调用系统原生的lowercaseString方法时,实际上调用的是分类里面的方法,在达到原来目的的同时,还能输出结果,非常方便!
注意:交换过后调用NSString原生的lowerCaseString实际上是调用xpp_myLowerCaseString;而在现在的xpp_myLowerCaseString里面,其实[self xpp_myLowerCaseString]实际上是调用了系统的lowerCaseString方法达到把字符串变为小写的目的。所以,不会陷入死循环!
一次性更改
假如今天你接到产品的需求,把App里面所有的字体减小两个点。你怎么办?搜索找工程里面的systemFontOfSize:
方法,挨个把字号-2;好,没问题,可以。那第二天她觉得这个字太小了,再加1个点吧^ _ ^。
这时候,方法交换技术派上用成了:
@interface UIFont (XppMyAdditions)
+ (UIFont *)xpp_systemFontOfSize:(CGFloat)size;
@end
@implementation UIFont (XppMyAdditions)
+ (UIFont *)xpp_systemFontOfSize:(CGFloat)size
{
UIFont *font = [self xpp_systemFontOfSize:(size-2)];
NSLog(@"%f---->%f",size, font.pointSize);
return font;
}
接下来,再把系统的方法和该方法交换一下:
Method m1 = class_getClassMethod([UIFont class], @selector(systemFontOfSize:));
Method m2 = class_getClassMethod([UIFont class], @selector(xpp_systemFontOfSize:));
method_exchangeImplementations(m1, m2);
注意:这里是类方法!不是实例方法,所以注意API的调用和分类方法要匹配,否则不会报错,但是你会发现没效果诶,这时候就太方便了,随便你想加2个点还是减1个点,无所谓,一个数字的事儿。
所以,从上看出,方法交换技术还是作用挺大的。只是尽量还是少用,一般就用来调试或者做些需要大量改动的处理。一般代码中不要为了show技术胡乱使用,这样会导致代码结构太差,用的多了,代码可读性也变差了,所以尽量还是少用,要不然哪天出bug了你都不知道问题在哪儿。合理使用即可!
网友评论