Objective-C 動(dòng)態(tài)生成中間類

有這樣一個(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類

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)星星哦

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莽鸭,隨后出現(xiàn)的幾起案子吗伤,更是在濱河造成了極大的恐慌,老刑警劉巖硫眨,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件足淆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡礁阁,警方通過查閱死者的電腦和手機(jī)巧号,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姥闭,“玉大人丹鸿,你說我怎么就攤上這事∨锲罚” “怎么了卜高?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)南片。 經(jīng)常有香客問我掺涛,道長(zhǎng),這世上最難降的妖魔是什么疼进? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任薪缆,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拣帽。我一直安慰自己疼电,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布减拭。 她就那樣靜靜地躺著蔽豺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拧粪。 梳的紋絲不亂的頭發(fā)上修陡,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音可霎,去河邊找鬼魄鸦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛癣朗,可吹牛的內(nèi)容都是我干的拾因。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼旷余,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼绢记!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起正卧,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤庭惜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后穗酥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體护赊,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年砾跃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骏啰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抽高,死狀恐怖判耕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翘骂,我是刑警寧澤壁熄,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站碳竟,受9級(jí)特大地震影響草丧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莹桅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一昌执、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦懂拾、人聲如沸煤禽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檬果。三九已至,卻和暖如春唐断,著一層夾襖步出監(jiān)牢的瞬間选脊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工栗涂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留知牌,地道東北人祈争。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓斤程,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親菩混。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忿墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容