runtime實操

runtime很早以前就聽說過,也試著寫過一些demo,但是總感覺在應(yīng)用中用不上,或者說不知道怎么使用;最初接觸的是叫Method Swizzling的東西,下面先講講Method Swizzling;
編程有一種叫做面向切片編程AOP,具體可以定義可以去wiki查看,大概就是把一些碎片的代碼跟主要功能分離;有個比較好的例子(這例子比較深刻)就是點擊按鈕或者進入某些特定界面,將這些用戶習(xí)慣發(fā)送到服務(wù)器做大數(shù)據(jù),這些邏輯實際上與應(yīng)用邏輯沒關(guān)系,所以讓他們占據(jù)在整個app中顯得不合適,具體看看實例:

Method Swizzling原理
每個類都維護一個方法(Method)列表,Method則包含SEL和其對應(yīng)IMP的信息,方法交換做的事情就是把SEL和IMP的對應(yīng)關(guān)系斷開,并和新的IMP生成對應(yīng)關(guān)系。
交換前:Asel->AImp Bsel->BImp
交換后:Asel->BImp Bsel->AImp
實操:

引入runtime,創(chuàng)建button實例

#import <objc/runtime.h>
@interface UIButton (ButtonSwizzling)

@end

.m文件實現(xiàn):

#import "ButtonSwizzling.h"
@implementation UIButton (ButtonSwizzling)
//應(yīng)該盡可能在+load方法中實現(xiàn),這樣可以保證方法一定會調(diào)用且不會出現(xiàn)異常
+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
              Class selfClass = [self class];
              SEL originSEL = @selector(endTrackingWithTouch:withEvent:);
             //獲取SEL的方法
             Method originMethod = class_getInstanceMethod(selfClass, originSEL);
             SEL newSEL = @selector(newendTrackingWithTouch:withEvent:);
             Method newMethod = class_getInstanceMethod(selfClass, newSEL);
             //class_addMethod是給方法添加實現(xiàn);getImplementation是獲取方法的實現(xiàn);getTypeEncoding獲取實現(xiàn)的編碼類型;
             //先嘗試給源方法添加實現(xiàn),這里是為了避免源方法沒有實現(xiàn)的情況
             bool succ = class_addMethod(selfClass, newSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
             if (succ) {
                             //取代實現(xiàn)
                            //添加成功:將源方法的實現(xiàn)替換到交換方法的實現(xiàn)
                             class_replaceMethod(selfClass, newSEL, method_getImplementation(originMethod),      method_getTypeEncoding(originMethod));
             } else {
                           //交換兩個方法的實現(xiàn)
                           //添加失?。赫f明源方法已經(jīng)有實現(xiàn),直接將兩個方法的實現(xiàn)交換即可
                           method_exchangeImplementations(originMethod, newMethod);
          }
      });
}
- (void)newendTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event {
        NSLog(@"BUTTON 方法改變啦");
       //事實上這里不是死循環(huán)哦,已經(jīng)被替換成sendAction:to:forEvent:
       [self newendTrackingWithTouch:touch withEvent:event];
}
@end

這樣你點擊button能看到console輸出"BUTTON 方法改變啦"!!
封裝swizzling有個很出名的庫,叫ASPECT!有興趣的可以去看看,不過感覺也沒差

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容