原文連接: kukumalucn.github.io/blog/2018/1…git
剛在羣裏看到這樣一段代碼,頗有意思:github
- (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");
}
複製代碼
這段代碼的執行結果會是什麼呢? 是打印「一、2」,仍是「一、三、2」,或者是「一、二、3」?面試
這實際上是一道頗有意思的面試題,內容涉及runloop這個知識點。 答案是隻打印:「一、2」。 緣由羣裏的大神給瞭解答:xcode
由於
[self performSelector:@selector(test) withObject:nil afterDelay:.0]
實際在runloop裏面,是一個定時器,可是由於在子線程,runloop是默認沒有開啓的。多線程
這除了涉及runloop,還有多線程的問題,有興趣的能夠深究。 其實咱們只要仔細閱讀蘋果API的註釋,就能解釋這個問題:async
想要執行-test
方法,註釋裏也提供瞭解決辦法:oop
[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:YES];
複製代碼
其實針對上述的邏輯,更簡單的是:ui
[self performSelector:@selector(test) withObject:nil];
複製代碼
之因此要提上述的問題,除了這個面試的「考點」,其實在平時的開發過程當中也要注意本身代碼的嚴謹性。 我發現本身在閱讀別人的代碼時,就見過一樣的寫法,其實甚至那些比較有名的三方庫,例如「YYText
」中,也有相似的代碼存在:spa
[self performSelector:@selector(test) withObject:nil afterDelay:0];
複製代碼
寫這段代碼的人只是爲了經過selector來馬上執行某一方法,delay
並非他們的需求,爲何還要「畫蛇添足」呢? 這裏一大部分緣由,極可能仍是由於咱們被xcode的自動提示給「慣壞了」:線程
畢竟當你寫代碼時,羅列的一堆提示,只是按照API類似度排列出來的,不少人看到了本身須要的就直接回車了,不須要delay
,直接寫0,就好了,反正「都同樣」…… 其實這是一個誤區,看起來很類似的API,實則並不同,並且很不同:
咱們經常使用的這個perform,是NSObject.h
這個頭文件下的方法:
能夠delay的,是NSRunLoop.h
下的方法:
而以前提到的回調主線程的,是NSThread.h
裏的方法:
雖然他們都是NSObject的方法或者是分類補充方法,但實際上,是隸屬於不一樣的模塊的。
可是「YYText
」的做者應該是不會犯這種低級錯誤的,那就應該還有更深入的緣由了:
咱們不少人應該老是會被上述的警告所困擾,大多數人的解決方式,就是利用相似相面的方式去屏蔽警告,這種作法雖然簡單,但實際是有風險的:
#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];
複製代碼
這種方式去避免警告的,看上面的那三個對比你就會發現,後兩類API,一樣是performSelector
,卻沒有返回值,這其實也是有官方註釋的依據的:
但其實你也要注意到了,官方的建議仍是很嚴謹的,是用performSelectorOnMainThread
,而不是delay0的方式,至於緣由,咱們又回到了文章一開頭的討論了。
經過上面看似無心義的探究,咱們仍是能夠獲得很深入的教訓的:「蘋果霸霸」仍是很嚴謹的,多看API的註釋,老是沒錯的。
本文做者: 霖溦
本文連接: kukumalucn.github.io/blog/2018/1…
版權聲明: 本博客全部文章除特別聲明外,均採用 CC BY-NC-ND 4.0 許可協議。轉載請註明出處!