工程中遇到拦截ViewController的viewWillAppear和viewWillDisappear方法,来对页面停留时间进行计算的问题.查找资料后,发现可以用runtime的方法交换来实现.
iOS应用启动时,会调用load加载类方法.所以可以新建分类Observer,在load方法中实现方法交换.具体实现如下:
@implementation UIViewController (Observer)
+ (void)load{
Method originalAppear = class_getInstanceMethod([self class], @selector(viewWillAppear:));
Method currentAppear = class_getInstanceMethod([self class], @selector(pagerIn:));
method_exchangeImplementations(originalAppear, currentAppear);
Method originalDisappear = class_getInstanceMethod([self class], @selector(viewWillDisappear:));
Method currentDisappear = class_getInstanceMethod([self class], @selector(pagerOut:));
method_exchangeImplementations(originalDisappear, currentDisappear);
}
- (void)pagerIn:(BOOL)animated{
NSString *className = NSStringFromClass([self class]);
if (className) {
//获取时间
}
[self pagerIn:animated];
}
- (void)pagerOut:(BOOL)animated{
NSString *className = NSStringFromClass([self class]);
if (className) {
//获取时间
}
[self pagerOut:animated];
}
@end
注意
以上用于交换的方法pagerIn和pagerOut中,都要调用自身,而不能调用[super 方法],因为会形成死循环.
在对sendAction:to:forEvent:进行方法交换时,在点击有些控件,如UIBarButton时,会出现崩溃,是因为方法交换会响应者链的顺序,可以换用如下方式解决:
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method origMethod = class_getInstanceMethod([self class], @selector(sendAction:to:forEvent:));
SEL origsel = @selector(sendAction:to:forEvent:);
Method swizMethod = class_getInstanceMethod([self class], @selector(ZDControl_sendAction:to:forEvent:));
SEL swizsel = @selector(ZDControl_sendAction:to:forEvent:);
BOOL addMehtod = class_addMethod([self class], origsel, method_getImplementation(swizMethod), method_getTypeEncoding(swizMethod));
class_isMetaClass([UIButton class]);
if (addMehtod)
{
class_replaceMethod([self class], swizsel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}
else
{
method_exchangeImplementations(origMethod, swizMethod);
}
});
}
- (void)ZDControl_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
if ([self isKindOfClass:[UIButton class]] && self.titleLabel.text.length > 0 ) {
//处理
}
[self ZDControl_sendAction:action to:target forEvent:event];
}
喜欢和关注都是对我的支持和鼓励~