method swizzling學習

參考1
參考2

Method Swizzling是一個改變selector的實際實現的一個方法。比如有A,B方法,通過Method Swizzling方法可以實現調用A方法時,實際上是在調用B方法,實現了偷梁換柱的黑魔法。

使用場景:完全改變一個方法的實現
比如viewDidAppear.方法有:
1.繼承后重寫(不要調用super方法)。
2.使用分類實現重名方法,那么在分類會覆蓋原類中得方法。
3.使用method swizzling。

示例
更改UIImage的imageNamed方法,當傳入的image為空是打印出錯。

#import <objc/runtime.h>
@implementation UIImage (Swizzle)

+ (void)load{
    static  dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        Class class = [self class];
        
        // SEL:獲取方法編號,根據SEL就能去對應的類找方法
        SEL originalSelector = @selector(imageNamed:);
        SEL swizzledSelector = @selector(custom_imageNamed:);
        
        // 獲取系統的方法(注意,如果是實例方法,使用class_getInstanceMethod)
        Method originalMethod = class_getClassMethod(class, originalSelector);
        // 獲取自定義方法
        Method swizzledMethod = class_getClassMethod(class, swizzledSelector);

        // 交換方法實現
        method_exchangeImplementations(originalMethod, swizzledMethod);
    });
}

+ (UIImage *)custom_imageNamed:(NSString*)imageName{
    
    /**
     *   調用[UIImage imageNamed:imageName]
         說明:因為custom_imageNamed和imageNamed互相交換.所以下面方法調用的實際上是imageNamed:方法,不會造成死循環
     */
    UIImage *image = [self custom_imageNamed:imageName];
    if (!image) {
        NSLog(@"圖片是空得!");
    }
    return image;
}

@end

注意點
1.Swizzling要再+ (void)load或者+(void) initialize里實現。
說明:由于method swizzling 會影響到類的全局狀態,所以要避免在并發處理中出現競爭的情況。+load方法是在程序啟動時調用,可取。而+initialize是在第一次初始化使用類時候調用,雖然也是個選擇,但是如果一直沒有使用這個,那么也就不會使用method swizzling了。

2.Swizzling在dispatch_once中執行
說明:原子性可以保證代碼只執行一次,而swizzling可以滿足需要。

3.私有方法也能替換

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

推薦閱讀更多精彩內容