runtime實(shí)操

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

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

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

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

@end

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

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

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

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

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