RunTime機制詳解(三)

方法交換(Method Swizzling),先來看看這兩張圖片瞭解一下方法的實現的步驟(圖片來源於網絡)。

一、方法未交前SEL與IMP是這樣的一一對應。


二、交換後SEL與IMP是這樣的對應關係。


三、具體代碼的實現是下面這樣。

+ (void)swizzleSelector:(SEL)originalSelector withSwizzledSelector:(SEL)swizzledSeletor{
    Class class = [self class];
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzleMethod = class_getInstanceMethod(class, swizzledSeletor);
    
    //若已經存在,則添加失敗
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    //若原來的方法並不存在,則添加即可
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSeletor, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }else{
        method_exchangeImplementations(originalMethod, swizzleMethod);
    }
}

四、方法交換的實際應用。——防止按鈕重複點擊。

(1)主要應用到了RunTime機制的動態添加屬性和方法交換。

(2)在UIButton的類別中.h文件添加屬性,timeInterval(表示第一次點擊幾秒之後再次點擊纔會響應)。

(3)動態添加屬性。

#pragma mark --- 動態添加屬性
- (NSTimeInterval)timeInterval{
    return [objc_getAssociatedObject(self, ButtonTimeInterval) doubleValue];
}
- (void)setTimeInterval:(NSTimeInterval)timeInterval{
    objc_setAssociatedObject(self, ButtonTimeInterval, @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
(4)方法交換。

#pragma mark --- load方法內進行方法互換(這個方法只會在初始化被調用一次)
+ (void)load{

    [self swizzleSelector:@selector(sendAction:to:forEvent:) withSwizzledSelector:@selector(custom_sendAction:to:forEvent:)];
  
}
(5)在自定義的要交換的方法中實現想要的效果。

#pragma mark --- 自定義方法的實現
- (void)custom_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
    if (self.pass)return;
    if (self.timeInterval > 0) {
        self.pass = YES;
        [self performSelector:@selector(resetPassValue) withObject:nil afterDelay:self.timeInterval];
    }
    [self custom_sendAction:action to:target forEvent:event];
}
- (void)resetPassValue{
    [self setPass:NO];
}

(6)聰明的你肯定是知道爲什麼最後自定的方法要實現自己調用自己呢?這纔是方法交換的本質嘛,調用自己其實就是在調用系統的實現方法。

代碼傳送門:https://github.com/fuzongjian/Runtime_ButtonClick.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章