iOS Method swizzling
原理:
1.發(fā)生在運(yùn)行時(shí),主要用于在運(yùn)行時(shí)將兩個(gè)方法交換镇匀。
2.代碼可以寫(xiě)在任何地方照藻,但是只有在這段交換代碼執(zhí)行完畢之后才起作用。
3.也是面向AOP(面向切面編程)的一種實(shí)現(xiàn)方式汗侵。
在OC語(yǔ)言的runtime特性中幸缕,調(diào)用一個(gè)對(duì)象的方法就是給這個(gè)對(duì)象發(fā)送消息,是通過(guò)查找接收消息對(duì)象的方法列表晰韵,從方法列表中查找對(duì)應(yīng)的SEL发乔,這個(gè)SEL對(duì)應(yīng)一個(gè)IMP(一個(gè)IMP對(duì)應(yīng)多個(gè)SEL),通過(guò)這個(gè)IMP找到對(duì)應(yīng)的方法調(diào)用宫屠。
在每個(gè)類中都有一個(gè)dispatch table列疗,這個(gè)Dispatch Table本質(zhì)是將類中的SEL和IMP(可以理解為函數(shù)指針)進(jìn)行對(duì)應(yīng)。而我們的Method Swizzling就是對(duì)這個(gè)table進(jìn)行了操作浪蹂,讓SEL對(duì)應(yīng)另一個(gè)IMP抵栈。
使用:
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class aclass = [self class];
SEL originalSelector = @selector(printName);
SEL swizzlingSelector = @selector(printSex);
Method originalMethod = class_getInstanceMethod(aclass, originalSelector);
Method swizzlingMethod = class_getInstanceMethod(aclass, swizzlingSelector);
method_exchangeImplementations(originalMethod, swizzlingMethod);
});
}
直接交換IMP是比較危險(xiǎn)的。因?yàn)槿绻@個(gè)類中如果沒(méi)有實(shí)現(xiàn)這個(gè)方法坤次,class_getInstanceMethod()
返回的是父類的method對(duì)象古劲,這樣交換的話,會(huì)把父類的原始實(shí)現(xiàn)(IMP)和這個(gè)類的Swizzle交換了缰猴,這樣就會(huì)出現(xiàn)問(wèn)題产艾。
所以如果類中沒(méi)有實(shí)現(xiàn) Original selector 對(duì)應(yīng)的方法,那就先添加 Method滑绒,并將其 IMP 映射為 Swizzle 的實(shí)現(xiàn)闷堡。然后替換 Swizzle selector 的 IMP 為 Original 的實(shí)現(xiàn);否則交換二者 IMP
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class aclass = [self class];
SEL originalSelector = @selector(printName);
SEL swizzlingSelector = @selector(printSex);
Method originalMethod = class_getInstanceMethod(aclass, originalSelector);
Method swizzlingMethod = class_getInstanceMethod(aclass, swizzlingSelector);
BOOL didAddMethod = class_addMethod(aclass, originalSelector, method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
if (didAddMethod) {
class_replaceMethod(aclass, swizzlingSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzlingMethod);
}
});
}