你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 一次關於OC運行時和Method Swizzing的小實踐

一次關於OC運行時和Method Swizzing的小實踐

編輯:IOS開發基礎

本文是投稿文章,作者:我是喬忘記瘋狂
起因

最近練習一個項目,經典的UITabBarController加UINavigationController的組合,茫茫多得頁面需要設置一個統一的背景色,起初在每個控制器的viewDidLoad方法中都加上這麼一段:

self.view.backgroundColor = WXGGlobalBackgroundColor; // 設置全局背景色

可是隨著開發的進行,控制器和界面越來越多,每一個控制器都要寫這麼一句同樣的代碼讓我感覺很煩,於是開始尋找一勞永逸的辦法。經旁人指點,這其實跟我們想要黑盒測試一個方法一樣,不管控制器的viewDidLoad方法做了什麼,最後都給他加上設置背景色的代碼就OK了。於是馬上想到用OC運行時中的Method Swizzing來搞。

經過

有了解決問題的思路,剩下的事就很簡單了。我就直接貼代碼了:

// UIViewController+Extension.h
#import @interface UIViewController (Extension)
@end
//
// UIViewController+Extension.m
#import "UIViewController+Extension.h"
#import @implementation UIViewController (Extension)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method originalMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));
        Method swizzledMethod = class_getInstanceMethod([self class], @selector(swizzled_viewDidLoad));
        BOOL didAddMethod = class_addMethod([self class], @selector(viewDidLoad), method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (didAddMethod) {
            class_replaceMethod([self class], @selector(swizzled_viewDidLoad), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}
- (void)swizzled_viewDidLoad {
    [self swizzled_viewDidLoad];
//    self.view.backgroundColor = WXGGlobalBackgroundColor;
//    NSLog(@"%@ loaded", self);
    if (![self isKindOfClass:NSClassFromString(@"UIInputWindowController")]) {
        self.view.backgroundColor = WXGGlobalBackgroundColor;
    }
}
@end

關於Method Swizzing的使用和最佳實踐,還是推薦去看Mattt大神的文章吧,鏈接在這裡,英文不好的同學可以看南峰子前輩翻譯好的,文章鏈接在這裡。

Method Swizzing的用法並不難,我就不過多解釋了。說一下碰到的問題:第一次寫完測試運行的時候,發現模擬器整個界面只有純色一片,看不到任何控件,進調試工具一看,所有控件都在也都正常,而且在模擬器上點擊對應控件的位置,仍然能夠觸發事件,整個界面就好像被人為塗了一層顏色一樣。一時不知該怎麼解決,只好NSLog一下,看看都有哪些控制器觸發了viewDidLoad方法,然後就真的發現了一個奇怪的家伙:

// 省略上面的輸出結果 loaded

而且這個家伙還是在最後一個,頓時對它懷疑大增,弄不好就是這家伙弄了個全屏的view給我塗在了屏幕上面。接下來就測試一下是不是它搞的鬼,代碼同上面的最終代碼,最後測試運行發現排除掉它之後界面立馬正常了,真的就是它搞的鬼。

結果

最後只能去查這個UIInputWindowController到底是個什麼東西,可惜沒有查到直接的結果,只知道它是一個蘋果的私有API,而且網上已經有人用運行時技術列出了它所包含的成員變量和方法。至於它到底是做什麼用的,我們可以從它的命名大致猜一下,多少應該是跟鍵盤輸入有關。我們都知道彈出的鍵盤也是一個UIWindow對象,不過有別於我們經常使用的keyWindow,那麼這些window對象誰來管理呢?可能這是一個思路。

最近時間有限,要繼續練習項目了,這個問題就暫時解決到這裡,就算是一次對OC運行時和Method Swizzing的小實踐吧。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved