iOS 關(guān)于Runtime的騷操作

CPFRuntimeKit

源代碼傳送門,編寫不易疤祭,看完給個Star哦湾揽。

用來做什么?

一個用來處理 Objective-C Runtime 騷操作的小工具踢关,包含一下幾個功能:

  • CPFRuntimeHelper —— 為你指定的Class提供便捷的Hacker方法伞鲫;
  • CPFRuntimeInvoker —— 為你指定的Class提供便捷的響應方法;
  • CPFWeakSingleton —— 一種另類的單例模式實現(xiàn)方式签舞,解決單例在生命周期不釋放的問題秕脓。
  • CPFTestClass —— 結(jié)合CPFRuntimeHelper,處理Runtime消息轉(zhuǎn)發(fā)儒搭。

一吠架、CPFRuntimeHelper

提供簡單易用的API用于快速獲取成員變量列表屬性列表搂鲫、類方法列表傍药、實例方法列表協(xié)議列表,此外還支持動態(tài)注入實例方法怔檩、交換實例方法實現(xiàn)等褪秀。

API如下:

  1. 獲取類實例的成員變量列表
+ (NSArray *)fetchIvarList:(Class)class;
  1. 獲取類實例的屬性列表
+ (NSArray *)fetchPropertyList:(Class)class;
  1. 獲取類實例的方法列表
+ (NSArray *)fetchMethodList:(Class)class;
  1. 為類實例動態(tài)添加實例方法,或者改變某methodSel的methodSelImpl
+ (void)addMethod:(Class)class method:(SEL)methodSel method:(SEL)methodSelImpl;
  1. 交換類實例的方法實現(xiàn)
+ (void)methodSwap:(Class)class firstMethod:(SEL)method1 secondMethod:(SEL)method2;

以上僅展示一些相關(guān)API薛训,具體說明和使用請參考Demo媒吗,內(nèi)附有完整注釋。

二乙埃、CPFRuntimeInvoker

與CPFRuntimeHelper不同闸英,CPFRuntimeInvoker的實現(xiàn)和調(diào)用方式主要有兩種,一種是為NSObject類添加Category介袜,這樣一來甫何,就能為所有的類,包括自定義的類添加實例方法類方法了遇伞。
CPFRuntimeInvoker就是利用了Category的特性為NSObject和NSString添加擴展辙喂,這樣就能通過Object和String,直接執(zhí)行私有方法鸠珠,并注入可變參數(shù)巍耗。

例如:

  1. 響應實例對象的私有方法,提供可變參數(shù)的注入渐排,用于不確定參數(shù)個數(shù)的私有方法
CPFTestClass *test = CPFTestClass.new;
[test invoke:@"testInvokSelectorWithArguments:arg2:" args:@"參數(shù)1",@"參數(shù)2",nil];
  1. 根據(jù) Class Name 響應私有方法
// CPFTestClass 是自定義類的類名
[@"CPFTestClass" invokeClassMethod:@"testClassMethod"];

以上僅展示一些相關(guān)API炬太,具體說明和使用請參考Demo,內(nèi)附有完整注釋驯耻。

特別的

除此之外亲族,里面一些實現(xiàn)的細節(jié)需要簡單的說明一下,最主要的是NSInvocation相關(guān)的理解:

  1. NSInvocation對象被用于對象存儲以及對象與Application之間的消息轉(zhuǎn)發(fā)可缚;
  2. 自定義NSInvocation對象霎迫,需要提供相應類型的NSMethodSignature對象、arguments帘靡、target知给、返回值類型等,對NSInvocation對象執(zhí)行 - invoke 方法测柠,來執(zhí)行響應的signature,并得到Return Type缘滥;
  3. 在2中提到的響應的arguments需要特別注意參數(shù)類型的問題轰胁,一旦類型出現(xiàn)錯誤可能引發(fā)意想不到的Crash。但萬幸的是NSMethodSignature對象提供 -getArgumentTypeAtIndex: 的實力方法朝扼,可以返回當前索引位置的參數(shù)類型赃阀,不過參數(shù)類型是 char * 型的;
  4. @encode 關(guān)鍵字,可以將類型轉(zhuǎn)換為 char * 型的字符串榛斯,如@encode(int) 观游,結(jié)合strcmp這個C標準函數(shù)可以判斷參數(shù)類型是否相同的問題;
  5. 執(zhí)行的返回結(jié)果驮俗,通過NSInvocation對象的 - getReturnValue: 實力方法得到懂缕,其中的參數(shù)是一個地址指針,用來指向返回值變量王凑;
  6. 除此之外搪柑,提供k_COVERT_ARRAY_FROM_args宏定義,用于將OC方法的可變參數(shù)轉(zhuǎn)換成NSArray索烹;
  7. 需要知道的是工碾,編譯器在處理可變參數(shù)的時候,是根據(jù)第一個可變參數(shù)在內(nèi)存中的地址百姓、參數(shù)類型渊额、偏移量等動態(tài)的計算出下一個參數(shù)的位置,從而取得相應的值垒拢,直到讀取到nil為止旬迹;
  8. 在6中的宏定義,就是利用了這個特性將可變參數(shù)轉(zhuǎn)換成NSArray的子库。

三舱权、CPFWeakSingleton

在開發(fā)中,我們通常會使用單例模式仑嗅,但是單例會有一個不好的問題就是宴倍,在整個程序的運行周期中,單例對象都不會被釋放仓技,從而會對內(nèi)存造成一定的影響鸵贬,那么我們可以利用 weak 關(guān)鍵字對單例模式進行改造,達到如果單例對象被外部持有脖捻,則永遠不會被釋放阔逼,一旦不被外部持有,則會在 Runloop 時被回收內(nèi)存的目的地沮。

以名為CPFWeakSingleton的類名為例嗜浮,代碼如下:

@implementation CPFWeakSingleton

+ (instancetype)sharedInstacne {
return [[self alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static __weak CPFWeakSingleton *weakInstance;
CPFWeakSingleton *strongInstance = weakInstance;
@synchronized(self) {
if (strongInstance == nil) {
strongInstance = [super allocWithZone:zone];
weakInstance = strongInstance;
}
}
return strongInstance;
}
@end

下面對其進行驗證:

_strongInstance = [CPFWeakSingleton sharedInstacne];
NSLog(@"1---%p",_strongInstance);
_strongInstance.testStr = @"保留所有權(quán)";
NSLog(@"2---%p",_strongInstance);

sleep(5);
NSLog(@"3---%p",[CPFWeakSingleton sharedInstacne]);

運行結(jié)果如下:

1---0x604000202ea0
2---0x604000202ea0
3---0x604000202ea0

可以看出,當我們通過_strongInstance變量持有單例對象時摩疑,在經(jīng)過 Runloop 之后危融,單例對象也不會被釋放(sleep函數(shù)是為了驗證 Runloop 后對象是否會被回收)。

然而我們對上例稍加改動雷袋,使_strongInstance被釋放后會發(fā)生什么呢吉殃?

_strongInstance = [CPFWeakSingleton sharedInstacne];
NSLog(@"1---%p",_strongInstance);
_strongInstance.testStr = @"保留所有權(quán)";
NSLog(@"2---%p",_strongInstance);

_strongInstance = nil;

sleep(5);
NSLog(@"3---%p",[CPFWeakSingleton sharedInstacne]);

此時的運行結(jié)果如下:

1---0x600000009430
2---0x600000009430
3---0x604000007570

可以看出,當外部的_strongInstance對象被釋放,不再持有單例對象的時候蛋勺,或者超出此時單例對象的作用域時(上述代碼未演示)瓦灶,該單例對象也會在 Runloop 中被系統(tǒng)回收,當我們再次使用sharedInstacne類方法獲取單例對象的時候抱完,則會創(chuàng)建一個新的單例對象贼陶。這樣,就能即使用單例乾蛤,又解決了產(chǎn)生的單例對象一直占用內(nèi)存資源每界,而且在整個程序的運行周期內(nèi)都不會被釋放的問題。

四家卖、CPFTestClass

有關(guān)消息轉(zhuǎn)發(fā)的一些內(nèi)容眨层,網(wǎng)上有很多相關(guān)的資料說的都很清楚,在這里就不做過多的贅述上荡。本Demo中主要是結(jié)合CPFRuntimeHelper和CPFRuntimeInvoker去強行實現(xiàn)消息轉(zhuǎn)發(fā)的過程趴樱,以及解決消息轉(zhuǎn)發(fā)帶來的doesNotRecognizeSelector異常Crash的問題。

以上僅展示一些相關(guān)API酪捡,具體說明和使用請參考Demo叁征,內(nèi)附有完整注釋。

源代碼傳送門逛薇,編寫不易捺疼,看完給個Star哦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末永罚,一起剝皮案震驚了整個濱河市啤呼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呢袱,老刑警劉巖官扣,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異羞福,居然都是意外死亡惕蹄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門治专,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卖陵,“玉大人,你說我怎么就攤上這事张峰±崮瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵挟炬,是天一觀的道長鸥滨。 經(jīng)常有香客問我,道長谤祖,這世上最難降的妖魔是什么婿滓? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮粥喜,結(jié)果婚禮上凸主,老公的妹妹穿的比我還像新娘。我一直安慰自己额湘,他們只是感情好卿吐,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锋华,像睡著了一般嗡官。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毯焕,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天衍腥,我揣著相機與錄音,去河邊找鬼纳猫。 笑死婆咸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的芜辕。 我是一名探鬼主播尚骄,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼侵续!你這毒婦竟也來了倔丈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唆貌,沒想到半個月后猎塞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡警儒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了眶根。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜀铲。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖属百,靈堂內(nèi)的尸體忽然破棺而出记劝,到底是詐尸還是另有隱情,我是刑警寧澤族扰,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布厌丑,位于F島的核電站定欧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏怒竿。R本人自食惡果不足惜砍鸠,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耕驰。 院中可真熱鬧爷辱,春花似錦、人聲如沸朦肘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媒抠。三九已至弟断,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趴生,已是汗流浹背夫嗓。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冲秽,地道東北人舍咖。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像锉桑,于是被迫代替她去往敵國和親排霉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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