Method Swizzling 的具體分析

OC 是一門動(dòng)態(tài)的語(yǔ)言, runtime 的機(jī)制給開(kāi)發(fā)者提供了許多新的可能, 在運(yùn)行時(shí), 可以動(dòng)態(tài)為一個(gè)類添加方法和屬性.

首先說(shuō)一下 objc_msgSend 執(zhí)行方法

現(xiàn)在我們有一個(gè) Doctor 類:

//  Doctor.m
@implementation Doctor

- (void)sayhello {
    NSLog(@"hello");
}
@end

我們都知道不在.h 里面申明, .只在 .m 中實(shí)現(xiàn)的方法, 就相當(dāng)于私有方法. 但并非只可以在.m 中調(diào)用.

Doctor *doctor = [[Doctor alloc] init];
#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [doctor performSelector:NSSelectorFromString(@"sayhello") withObject:nil];
#pragma clang diagnostic pop

使用 perfromSelector 就可以直接掉用知道名字的方法.

perfromSelector相當(dāng)于:

Doctor *doctor = [[Doctor alloc] init];
SEL sel = NSSelectorFromString(@"sayhello");
void (*sendMsg)(id, SEL) = (void (*)(id, SEL))objc_msgSend;
sendMsg(doctor, sel);

runtime 中使用 objc_msgSend 來(lái)執(zhí)行所有的方法.

class_addMethod 動(dòng)態(tài)添加方法

SEL sel = NSSelectorFromString(@"sayhello");
// 獲取當(dāng)前類 method
Method method = class_getInstanceMethod([self class], NSSelectorFromString(@"sayhello"));
// 讓 Doctor 指向當(dāng)前類的 method
class_addMethod([doctor class], sel, method_getImplementation(method), method_getTypeEncoding(method));

//當(dāng)前類聲明一個(gè)方法
- (void)sayhello {
    NSLog(@"hello");
}

Method Swizzling

@implementation UIViewController (Tracking)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        
        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(xxx_viewWillAppear:);
        
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        // 將 originalMethod 指向 xxx_viewWillAppear: 的實(shí)現(xiàn).
        BOOL didAddMethod = 
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
    // 將 swizzledMethod 指向 viewWillAppear: 的實(shí)現(xiàn).
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated]; // 這里實(shí)際執(zhí)行的是 viewWillAppear:
}

通過(guò)調(diào)換兩個(gè)方法的實(shí)現(xiàn), 來(lái)實(shí)現(xiàn), 捕捉原始方法的執(zhí)行. 當(dāng)需要捕捉某個(gè)方法執(zhí)行, 一種方法是通過(guò)繼承來(lái)實(shí)現(xiàn), 另一種方法通過(guò) Method Swizzling, 當(dāng)有很多不同形態(tài)的子類存在的時(shí)候, 繼承還是需要寫很多重復(fù)代碼.

首先說(shuō)一下, 當(dāng)通過(guò) Method Swizzling 交換方法之后, 所有這個(gè)類的子類走這個(gè)交換過(guò)的方法都會(huì), 在當(dāng)前的實(shí)現(xiàn)中捕捉到, 所以, 在這個(gè)方法中的 self 是會(huì)發(fā)生變化的, 可能是任意一個(gè) UIViewController 的子類.
即:

// 所有 UIViewController 的子類和本身, 在走 viewWillAppear 之前都會(huì)走下面的方法
- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated]; // 這里實(shí)際執(zhí)行的是 viewWillAppear:
}

@sunnyxib的動(dòng)態(tài)橋接 中, 他捕捉了所有的 UIView 子類的 awakeAfterUsingCoder 方法, 并通過(guò)判斷是否遵守協(xié)議來(lái)判斷是否要進(jìn)行處理, 所以只有在 UIView 子類種, 遵守 XXNibBridge 協(xié)議的子類才會(huì)被動(dòng)態(tài)加載, 這是 Method Swizzling 一個(gè)很好的案例.

// 交換后的方法
- (id)hackedAwakeAfterUsingCoder:(NSCoder *)decoder {
    if ([self.class conformsToProtocol:@protocol(XXNibBridge)] && ((UIView *)self).subviews.count == 0) {
        // "self" is placeholder view for this moment, replace it.
        return [XXNibBridgeImplementation instantiateRealViewFromPlaceholder:(UIView *)self];
    }
    return self;
}

Method Swizzling @Mattt Thompson
xib的動(dòng)態(tài)橋接 @sunny

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末空镜,一起剝皮案震驚了整個(gè)濱河市浩淘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吴攒,老刑警劉巖张抄,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異洼怔,居然都是意外死亡署惯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門镣隶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)极谊,“玉大人诡右,你說(shuō)我怎么就攤上這事∏岵” “怎么了帆吻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)咙边。 經(jīng)常有香客問(wèn)我猜煮,道長(zhǎng),這世上最難降的妖魔是什么败许? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任王带,我火速辦了婚禮,結(jié)果婚禮上檐束,老公的妹妹穿的比我還像新娘辫秧。我一直安慰自己束倍,他們只是感情好被丧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著绪妹,像睡著了一般甥桂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邮旷,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天黄选,我揣著相機(jī)與錄音,去河邊找鬼婶肩。 笑死办陷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的律歼。 我是一名探鬼主播民镜,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼险毁!你這毒婦竟也來(lái)了制圈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤畔况,失蹤者是張志新(化名)和其女友劉穎鲸鹦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跷跪,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馋嗜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吵瞻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌戈。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡覆积,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出熟呛,到底是詐尸還是另有隱情宽档,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布庵朝,位于F島的核電站吗冤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏九府。R本人自食惡果不足惜椎瘟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侄旬。 院中可真熱鬧肺蔚,春花似錦、人聲如沸儡羔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)汰蜘。三九已至仇冯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間族操,已是汗流浹背苛坚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留色难,地道東北人泼舱。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像枷莉,于是被迫代替她去往敵國(guó)和親娇昙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉依沮,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評(píng)論 0 9
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 729評(píng)論 0 2
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 751評(píng)論 0 1
  • 本文轉(zhuǎn)自:楊蕭玉博客 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)涯贞,它使得 Objective-C ...
    oneofai閱讀 204評(píng)論 0 0
  • 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí),它使得 Objective-C 如虎添翼危喉,具備了靈活的...
    lylaut閱讀 795評(píng)論 0 4