iOS中runtime实现方法交换sendAction:to:forEvent:

工程中遇到拦截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];
}

喜欢和关注都是对我的支持和鼓励~

你可能感兴趣的:(iOS中runtime实现方法交换sendAction:to:forEvent:)