缘由:最近在看项目的时候,有时发现哪个界面出现了,却不知道代码中具体在什么地方,为了达到这一需求,就很自然的用到了
Method Swizzling
,通过如下代码很容易实现以上这个要求。
#import "UIViewController+Swizzling.h"
#import <objc/runtime.h>
@implementation UIViewController (Swizzling)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(ypq_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (void)ypq_viewWillAppear:(BOOL)animated {
[self ypq_viewWillAppear:animated];
NSLog(@"viewApperarClassName===%@", NSStringFromClass([self class]));
}
备注:http://nshipster.com/method-swizzling/
我在使用老项目的时候,还遇到一次不起效果的情况,后来发现的是原来项目中已经有了一个UIViewController 的Category啦,所以我们加入在用的时候也需要注意这个。
Method Swizzling
是改变一个selector
的实际实现的技术。通过这一技术,我们可以在运行时通过修改类的分发表中selector
对应的函数,来修改方法的实现。
扩展
再看
Effective Objective-C 2.0
中的一个例子
#import <Foundation/Foundation.h>
@interface NSString (YPQAddtions)
- (NSString *)ypq_myLowercaseString;
@end
#import "NSString+YPQAddtions.h"
@implementation NSString (YPQAddtions)
- (NSString *)ypq_myLowercaseString {
NSString *lowercase = [self ypq_myLowercaseString];
NSLog(@"%@ => %@",self,lowercase);
return lowercase;
}
@end
上面那段代码看上去好像陷入递归调用的死循环,不过,此方法是准备和lowercaseString
方法互换的。所以,在运行期ypq_myLowercaseString
选择子实际上对应于原有的 lowercaseString
方法实现的。
// 具体执行
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString class], @selector(ypq_myLowercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
// 测试
NSString *testString = @"I am A BAd Man";
NSString *lowercaseString = [testString lowercaseString];
NSLog(@"lowercaseString === %@",lowercaseString);
// OutPut
/**
I am A BAd Man => i am a bad man
lowercaseString === i am a bad man
*/
通过此方案,我们可以为那些“完全不知道其具体怎么实现的”黑盒方法增加日志记录功能,这非常有助于调试。
需要了解更多,可看下面的一些链接
http://tech.glowing.com/cn/method-swizzling-aop/
http://southpeak.github.io/blog/2014/11/06/objective-c-runtime-yun-xing-shi-zhi-si-:method-swizzling/
http://blog.csdn.net/yiyaaixuexi/article/details/9374411