Method Swizzling是一個(gè)改變selector的實(shí)際實(shí)現(xiàn)的一個(gè)方法。比如有A,B方法,通過Method Swizzling方法可以實(shí)現(xiàn)調(diào)用A方法時(shí),實(shí)際上是在調(diào)用B方法,實(shí)現(xiàn)了偷梁換柱的黑魔法。
使用場(chǎng)景:完全改變一個(gè)方法的實(shí)現(xiàn)
比如viewDidAppear.方法有:
1.繼承后重寫(不要調(diào)用super方法)。
2.使用分類實(shí)現(xiàn)重名方法,那么在分類會(huì)覆蓋原類中得方法。
3.使用method swizzling。
示例
更改UIImage的imageNamed方法,當(dāng)傳入的image為空是打印出錯(cuò)。
#import <objc/runtime.h>
@implementation UIImage (Swizzle)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
Class class = [self class];
// SEL:獲取方法編號(hào),根據(jù)SEL就能去對(duì)應(yīng)的類找方法
SEL originalSelector = @selector(imageNamed:);
SEL swizzledSelector = @selector(custom_imageNamed:);
// 獲取系統(tǒng)的方法(注意,如果是實(shí)例方法,使用class_getInstanceMethod)
Method originalMethod = class_getClassMethod(class, originalSelector);
// 獲取自定義方法
Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
// 交換方法實(shí)現(xiàn)
method_exchangeImplementations(originalMethod, swizzledMethod);
});
}
+ (UIImage *)custom_imageNamed:(NSString*)imageName{
/**
* 調(diào)用[UIImage imageNamed:imageName]
說明:因?yàn)閏ustom_imageNamed和imageNamed互相交換.所以下面方法調(diào)用的實(shí)際上是imageNamed:方法,不會(huì)造成死循環(huán)
*/
UIImage *image = [self custom_imageNamed:imageName];
if (!image) {
NSLog(@"圖片是空得!");
}
return image;
}
@end
注意點(diǎn)
1.Swizzling要再+ (void)load或者+(void) initialize里實(shí)現(xiàn)。
說明:由于method swizzling 會(huì)影響到類的全局狀態(tài),所以要避免在并發(fā)處理中出現(xiàn)競(jìng)爭(zhēng)的情況。+load方法是在程序啟動(dòng)時(shí)調(diào)用,可取。而+initialize是在第一次初始化使用類時(shí)候調(diào)用,雖然也是個(gè)選擇,但是如果一直沒有使用這個(gè),那么也就不會(huì)使用method swizzling了。
2.Swizzling在dispatch_once中執(zhí)行
說明:原子性可以保證代碼只執(zhí)行一次,而swizzling可以滿足需要。
3.私有方法也能替換