原文鏈接: https://kukumalucn.github.io/blog/2018/11/16/關(guān)于performSelector的一點注意/
前言
剛在群里看到這樣一段代碼垫释,很有意思:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:0];
NSLog(@"2");
});
}
- (void)test
{
NSLog(@"3");
}
這段代碼的執(zhí)行結(jié)果會是什么呢蒸绩?
是打印“1颈嚼、2”逃默,還是“1屿聋、3咧欣、2”凡泣,或者是“1枉疼、2皮假、3”?
內(nèi)容
1.問題探究
這其實是一道很有意思的面試題骂维,內(nèi)容涉及runloop這個知識點惹资。
答案是只打印:“1航闺、2”褪测。
原因群里的大神給了解答:
因為
[self performSelector:@selector(test) withObject:nil afterDelay:.0]
實際在runloop里面,是一個定時器来颤,但是因為在子線程汰扭,runloop是默認(rèn)沒有開啟的。
這除了涉及runloop福铅,還有多線程的問題萝毛,有興趣的可以深究。
其實我們只要仔細(xì)閱讀蘋果API的注釋滑黔,就能解釋這個問題:
想要執(zhí)行-test
方法笆包,注釋里也提供了解決辦法:
[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:YES];
其實針對上述的邏輯,更簡單的是:
[self performSelector:@selector(test) withObject:nil];
2.引發(fā)的思考
2.1.不要懶
之所以要提上述的問題略荡,除了這個面試的“考點”庵佣,其實在平時的開發(fā)過程中也要注意自己代碼的嚴(yán)謹(jǐn)性。
我發(fā)現(xiàn)自己在閱讀別人的代碼時汛兜,就見過同樣的寫法巴粪,其實甚至那些比較有名的三方庫,例如“YYText
”中粥谬,也有類似的代碼存在:
[self performSelector:@selector(test) withObject:nil afterDelay:0];
寫這段代碼的人只是為了通過selector來立刻執(zhí)行某一方法肛根,delay
并不是他們的需求,為什么還要“多此一舉”呢漏策?
這里一大部分原因派哲,很可能還是因為我們被xcode的自動提示給“慣壞了”:
畢竟當(dāng)你寫代碼時,羅列的一堆提示掺喻,只是按照API相似度排列出來的芭届,很多人看到了自己需要的就直接回車了,不需要delay
感耙,直接寫0褂乍,就行了,反正“都一樣”……
其實這是一個誤區(qū)即硼,看起來很相似的API树叽,實則并不一樣,而且很不一樣:
- 我們常用的這個perform谦絮,是
NSObject.h
這個頭文件下的方法:
- 可以delay的题诵,是
NSRunLoop.h
下的方法:
- 而之前提到的回調(diào)主線程的洁仗,是
NSThread.h
里的方法:
雖然他們都是NSObject的方法或者是分類補充方法,但實際上性锭,是隸屬于不同的模塊的赠潦。
2.2.更深刻的原因
但是“YYText
”的作者應(yīng)該是不會犯這種低級錯誤的,那就應(yīng)該還有更深刻的原因了:
我們很多人應(yīng)該總是會被上述的警告所困擾草冈,大多數(shù)人的解決方式她奥,就是利用類似相面的方式去屏蔽警告,這種做法雖然簡單怎棱,但實際是有風(fēng)險的:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//code
#pragma clang diagnostic pop
其實除了利用IMP
或者NSInvocation
那種比較“高端”的方式哩俭,更多的情況下,在方法沒有返回值時拳恋,或者我們不需要返回值時凡资,我們可以用:
[self performSelector:@selector(test) withObject:nil afterDelay:0];
這種方式去避免警告的,看上面的那三個對比你就會發(fā)現(xiàn)谬运,后兩類API隙赁,同樣是performSelector
,卻沒有返回值梆暖,這其實也是有官方注釋的依據(jù)的:
但其實你也要注意到了伞访,官方的建議還是很嚴(yán)謹(jǐn)?shù)模怯?code>performSelectorOnMainThread轰驳,而不是delay0的方式厚掷,至于原因,我們又回到了文章一開頭的討論了级解。
總結(jié)
通過上面看似無意義的探究冒黑,我們還是可以得到很深刻的教訓(xùn)的:“蘋果霸霸”還是很嚴(yán)謹(jǐn)?shù)模嗫碅PI的注釋蠕趁,總是沒錯的薛闪。
本文作者: 霖溦
原文鏈接: https://kukumalucn.github.io/blog/2018/11/16/關(guān)于performSelector的一點注意/
本文鏈接: 關(guān)于performSelector:afterDelay:的一個坑及思考
版權(quán)聲明: 本博客所有文章除特別聲明外辛馆,均采用 CC BY-NC-ND 4.0 許可協(xié)議俺陋。轉(zhuǎn)載請注明出處!