有這樣一個(gè)需求:
類Target喳坠,聲明兩個(gè)類Target的實(shí)例targetA暴氏,targetB厅贪;
當(dāng)實(shí)例targetA調(diào)用方法oriMethod時(shí)山涡,調(diào)用oriMethod;
當(dāng)實(shí)例targetB調(diào)用方法oriMethod時(shí),則實(shí)際調(diào)用的是hook之后的方法targetMethod
Target *targetA = [[Target alloc] init];
Target *targetB = [[Target alloc] init];
[targetA oriMethod]; ? ?//輸出:原方法oriMethod
[targetB oriMethod]; ? ?//輸出:新方法targetMethod
當(dāng)面對(duì)上述需求時(shí)必怜,Objective-C的動(dòng)態(tài)性優(yōu)勢(shì)就顯示出來啦肉拓;
具體實(shí)現(xiàn)原理類同KVO底層原理,給targetB類添加觀察者梳庆,在觀察方法中動(dòng)態(tài)的生成一個(gè)中間類暖途,然后在中間類中將方法oriMethod和targetMethod進(jìn)行methodSwizzing;
具體實(shí)現(xiàn)步驟:
創(chuàng)建一個(gè)NSObject的Category,(NSObject+Swizzing.h),在類中添加兩個(gè)方法
/// 添加觀察方法
/// @param observer 目標(biāo)類
/// @param oriMethod 原始方法
/// @param targetMethod 目標(biāo)替換方法
- (void)ltAddObserver:(NSObject*)observer forOriMethod:(NSString*)oriMethod byNewMethod:(NSString*)targetMethod;
/// 移除觀察方法
/// @param observer 目標(biāo)類
/// @param oriMethod 原始方法
- (void)ltRemoveObserver:(NSObject*)observer forOriMethod:(NSString*)oriMethod;
判斷原始方法(oriMethod)是否存在膏执,如果不存在驻售,那么直接返回,沒必要進(jìn)行后續(xù)操作
- (BOOL)judgeMethodIsExist:(NSString*)method{
????Class curClass =object_getClass(self);
????SEL oriSel =NSSelectorFromString(method);
????Method oriMethod =class_getInstanceMethod(curClass, oriSel);
????if(!oriMethod) {
????????return false;
? ? }
????return true;
}
動(dòng)態(tài)生成中間類
- (Class)dynamicCreateClass{
????NSString*oriClassName =NSStringFromClass([selfclass]);
????NSString*newClassName = [NSString stringWithFormat:@"%@%@",methodPrefix, oriClassName];
????Class newClass =NSClassFromString(newClassName);
????//申請(qǐng)類
????newClass =objc_allocateClassPair([self class], newClassName.UTF8String,0);
????//注冊(cè)
????objc_registerClassPair(newClass);
????//添加class方法(class用來修改isa)
????SEL classSel =@selector(class);
????Method classMethod =class_getInstanceMethod([self class], classSel);
????const char *classType =method_getTypeEncoding(classMethod);
????class_addMethod(newClass, classSel, (IMP)lt_class, classType);
????//添加dealloc方法
????SEL deallocSel =NSSelectorFromString(@"dealloc");
????Method deallocMethod =class_getInstanceMethod([self class], deallocSel);
????const char*deallocType =method_getTypeEncoding(deallocMethod);
????class_addMethod(newClass, deallocSel, (IMP)lt_dealloc, deallocType);
????//添加方法
????return newClass;
}
lt_class方法實(shí)現(xiàn)更米,用來將iSA返回父類
Class lt_class(id self,SEL _cmd){
????return class_getSuperclass(object_getClass(self));
}
lt_dealloc方法欺栗,對(duì)象釋放會(huì)自動(dòng)調(diào)用
void lt_dealloc(id self,SEL _cmd){
????Class superClass = [self class];
????object_setClass(self, superClass);
}
交換的核心方法
+ (BOOL)lt_hookOriInstanceMethod:(Class)cls oriSel:(SEL)oriSel newInstanceMethod:(SEL)newSel{
????Method oriMethod =class_getInstanceMethod(cls, oriSel);
????Method newMethod =class_getInstanceMethod(cls, newSel);
????//如果不存在原始方法,那么添加一個(gè)空的方法,什么也不做迟几,防止死循環(huán)
????if(!oriMethod) {
????????class_addMethod(cls,
oriSel,method_getImplementation(newMethod),method_getTypeEncoding(newMethod));
? ? ? ? ? ?method_setImplementation(newMethod,imp_implementationWithBlock(^(id self,SEL _cmd){}));
? ? }
????//交換方法
????//步驟:
????//1消请、先添加方法,如果添加不成功瘤旨,那么說明原始類中存在方法,直接交換即可
????//2竖伯、如果添加成功存哲,說明原始類中不存在方法,那么直接replace
????BOOL addMethod =class_addMethod(cls, oriSel,method_getImplementation(newMethod),method_getTypeEncoding(newMethod));
????if(!addMethod) {
????????method_exchangeImplementations(oriMethod, newMethod);
????}else{
????????class_replaceMethod(cls, newSel,method_getImplementation(oriMethod),method_getTypeEncoding(oriMethod));
? ? }
????return true;
}
以上就是動(dòng)態(tài)生成類以及類中添加方法的核心代碼七婴;
需要注意的是:
在ltAddObserver方法中祟偷,中間類創(chuàng)建出來后,一定要將修改iSA指向打厘,否則調(diào)不到修肠;
在ltRemoveObserver方法中,主要實(shí)現(xiàn)在移除觀察之后户盯,將iSA指針指回去嵌施;
還里利用associatedObject將被觀察類和方法添加到全局表中(存儲(chǔ)的是model信息)
具體代碼實(shí)現(xiàn)?喜歡記得點(diǎn)星星哦