performSelector may cause a leak because its selector is unknown解決

單純消除 warning:

LLVM 3.0 編譯器可以用以下代碼消除 warning:

#pragmaclang diagnostic push#pragmaclang diagnostic ignored"-Warc-performSelector-leaks"[self.ticketTarget performSelector: self.ticketAction withObject: self];#pragmaclang diagnostic pop屈梁。

#define SuppressPerformSelectorLeakWarning(Stuff) \do{ \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \ Stuff; \ _Pragma("clang diagnostic pop") \ }while(0)

用的時(shí)候? SuppressPerformSelectorLeakWarning( [_target performSelector:_action withObject:self]);

答案:

if(!_controller) {return; }SEL selector =NSSelectorFromString(@"someMethod");IMP imp = [_controller methodForSelector:selector];void(*func)(id, SEL) = (void*)imp;func(_controller, selector);

代碼解釋

這一堆代碼在做的事情其實(shí)是裆馒,向 controller 請(qǐng)求那個(gè)方法對(duì)應(yīng)的 C 函數(shù)指針。所有的NSObject都能響應(yīng)methodForSelector:這個(gè)方法葛家,不過也可以用 Objective-C runtime 里的class_getMethodImplementation(只在 protocol 的情況下有用,id這樣的)泌类。這種函數(shù)指針叫做IMP癞谒,就是typedef過的函數(shù)指針(id (*IMP)(id, SEL, ...)[1])。它跟方法簽名(signature)比較像,雖然可能不是完全一樣弹砚。

得到IMP之后双仍,還需要進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換后的函數(shù)指針包含 ARC 所需的那些細(xì)節(jié)(比如每個(gè) OC 方法調(diào)用都有的兩個(gè)隱藏參數(shù)self和_cmd)桌吃。這就是代碼第 4 行干的事(右邊的那個(gè)(void *)只是告訴編譯器朱沃,不用報(bào)類型強(qiáng)轉(zhuǎn)的 warning)。

更復(fù)雜的例子

如果 selector 接收參數(shù)茅诱,或者有返回值逗物,代碼就需要改改:

SEL selector =NSSelectorFromString(@"processRegion:ofView:");IMP imp = [_controller methodForSelector:selector];CGRect(*func)(id, SEL,CGRect,UIView*) = (void*)imp;CGRectresult = _controller ?? func(_controller, selector, someRect, someView) :CGRectZero;

為什么會(huì)有這個(gè) warning

原因是這樣的:我們?cè)?ARC 下調(diào)一個(gè)方法,runtime 需要知道對(duì)于返回值該怎么辦让簿。返回值可能有各種類型:void敬察,int,char尔当,NSString *莲祸,id等等。ARC 一般是根據(jù)返回值的頭文件來決定該怎么辦的椭迎,一共有以下 4 種情況:

直接忽略(如果是基本類型比如void锐帜,int這樣的)。

把返回值先 retain畜号,等到用不到的時(shí)候再 release(最常見的情況)缴阎。

不 retain,等到用不到的時(shí)候直接 release(用于init简软、copy這一類的方法蛮拔,或者標(biāo)注ns_returns_retained的方法)。

什么也不做痹升,默認(rèn)返回值在返回前后是始終有效的(一直到最近的 release pool 結(jié)束為止建炫,用于標(biāo)注ns_returns_autoreleased的方法)。

而調(diào)performSelector:的時(shí)候疼蛾,系統(tǒng)會(huì)默認(rèn)返回值并不是基本類型肛跌,但也不會(huì) retain、release察郁,也就是默認(rèn)采取第 4 種做法衍慎。所以如果那個(gè)方法本來應(yīng)該屬于前 3 種情況,都有可能會(huì)造成內(nèi)存泄漏皮钠。

對(duì)于返回void或者基本類型的方法稳捆,就目前而言你可以忽略這個(gè) warning,但這樣做不一定安全麦轰。我看過 Clang 在處理返回值這塊兒的幾次迭代演進(jìn)眷柔。一旦開著 ARC期虾,編譯器會(huì)覺得從performSelector:返回的對(duì)象沒理由不能 retain,不能 release驯嘱。在編譯器眼里镶苞,它就是個(gè)對(duì)象。所以鞠评,如果返回值是基本類型或者void茂蚓,編譯器還是存在會(huì) retain、release 它的可能剃幌,然后直接導(dǎo)致 crash聋涨。

帶參數(shù)調(diào)用

類似地,performSelector:withObject:也會(huì)報(bào)同一個(gè) warning负乡,因?yàn)椴恢该髟趺刺幚韰?shù)也會(huì)有同樣的問題牍白。ARC 允許為方法參數(shù)標(biāo)注consumed,如果你調(diào)的方法有這種標(biāo)注抖棘,最終可能導(dǎo)致把消息發(fā)給僵尸對(duì)象然后 crash茂腥。要解決這個(gè)問題可以用橋接(bridged casting),但是最好最簡(jiǎn)單的方法還是我上面寫的用IMP和函數(shù)指針的方法切省。不過給參數(shù)標(biāo) consumed 是比較少見的最岗,所以這個(gè)問題也不容易發(fā)生。

靜態(tài) selector

有趣的是朝捆,下面這種靜態(tài)聲明的 selector 就不會(huì)出 warning:

[_controller performSelector:@selector(someMethod)];

原因是般渡,這種情況下編譯器就能在編譯階段得到關(guān)于這個(gè) selector 的全部信息,不需要默認(rèn)任何事情

所有的 Objective-C 方法都有兩個(gè)隱藏的參數(shù)芙盘,self和_cmd驯用,調(diào)用時(shí)自動(dòng)加的。?

在 C 里調(diào)用NULL方法是不安全的儒老。而if (!_controller) { return; }這一句保證controller不為空蝴乔,所以我們一定能從methodForSelector:得到一個(gè)IMP(雖然可能只是_objc_msgForward,進(jìn)入消息轉(zhuǎn)發(fā)系統(tǒng))贷盲√哉猓基本上剥扣,有了這行檢查巩剖,就能保證我們有方法可調(diào)。?

實(shí)際上钠怯,如果返回值的類型是id佳魔,而你又沒 import 對(duì)應(yīng)的頭文件,它是有可能做出錯(cuò)誤處理的晦炊。有可能會(huì) crash 在一塊編譯器以為安全的代碼里鞠鲜。這種情況很罕見宁脊,但還是有發(fā)生的可能。一般來說贤姆,如果編譯器不知道該選哪個(gè)方法簽名榆苞,它會(huì)報(bào)一個(gè) warning 的。?

更多細(xì)節(jié)請(qǐng)參考 ARC 的文檔retain 返回值不 retain 返回值霞捡。

2.使用宏忽略警告

#define SuppressPerformSelectorLeakWarning(Stuff) \

do { \

_Pragma("clang diagnostic push") \

_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \

Stuff; \

_Pragma("clang diagnostic pop") \

} while (0)

在產(chǎn)生警告也就是 performSelector 的地方用使用該宏坐漏,如

SuppressPerformSelectorLeakWarning(

[_target performSelector:_action withObject:self]

);

如果需要 performSelector 返回值的話,

id result;

SuppressPerformSelectorLeakWarning(

result = [_target performSelector:_action withObject:self]

);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碧信,一起剝皮案震驚了整個(gè)濱河市赊琳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌砰碴,老刑警劉巖躏筏,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呈枉,居然都是意外死亡趁尼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門碴卧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弱卡,“玉大人,你說我怎么就攤上這事住册∩舨” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵荧飞,是天一觀的道長(zhǎng)凡人。 經(jīng)常有香客問我,道長(zhǎng)叹阔,這世上最難降的妖魔是什么挠轴? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮耳幢,結(jié)果婚禮上岸晦,老公的妹妹穿的比我還像新娘。我一直安慰自己睛藻,他們只是感情好启上,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著店印,像睡著了一般冈在。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上按摘,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天包券,我揣著相機(jī)與錄音纫谅,去河邊找鬼。 笑死溅固,一個(gè)胖子當(dāng)著我的面吹牛付秕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侍郭,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盹牧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了励幼?” 一聲冷哼從身側(cè)響起汰寓,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苹粟,沒想到半個(gè)月后有滑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嵌削,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年毛好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苛秕。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肌访,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出艇劫,到底是詐尸還是另有隱情吼驶,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布店煞,位于F島的核電站蟹演,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏顷蟀。R本人自食惡果不足惜酒请,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸣个。 院中可真熱鬧羞反,春花似錦、人聲如沸囤萤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阁将。三九已至膏秫,卻和暖如春右遭,著一層夾襖步出監(jiān)牢的瞬間做盅,已是汗流浹背缤削。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吹榴,地道東北人亭敢。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像图筹,于是被迫代替她去往敵國和親帅刀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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