之前開發過程中經常會有需求會使用 NSObject
中的"performSelector:withObject:afterDelay:"做方法延遲執行的處理, 但是 還沒有什么地方需要實現 取消 這個延遲執行方法"cancelPreviousPerformRequestsWithTarget:".(具體可參見系統庫文件 NSOject里面兩個方法的聲明).
但是 我們應該知道在什么條件下,合理使用 延遲 與 取消延遲.
延遲 和 取消延遲 應該 在同一個 事件處理循環(Run loop)里,不然 是無法取消的. (之前 不知道 啥叫 Run loop 哭~ 因為突然要使用 取消延遲執行的方法 才了解到的)
Run loop :一般程序至少有一個線程,那么這個線程是主線程, 而這個線程上會有一個 runloop(負責所有主線程的事件,包括UI事件) 一直在循環,就是我理解的事件處理循環,它會一直監聽 是否有相應的觸發動作(人為也好,內部機制也好),有則會立即做出對對應消息的響應,沒有則處於等待狀態甚至休眠.那么 我可以說 這個 run loop 是依附在對應的線程里面的.它的生命周期隨着線程的啟動終止等變化而變化.
在 蘋果官方文檔里還有示意圖,詳細講解,我理解的"觸發動作"即 "源事件"
Runloop接收兩種源事件:input sources和timer sources。
input sources 傳遞異步事件,通常是來自其他線程和不同的程序中的消息;(基於端口的輸入源,自定義輸入源,Cocoa上的Selector源)
timer sources(定時器) 傳遞同步事件(重復執行或者在特定時間上觸發)。//如果要設定NSTimer 要在當前的Run loop 里設定(一般在主線程里),在子線程里面設置NSTime,要獲取子線程的Run loop,才有效 "[[NSRunLoop currentRunLoop] addTimer:.....]"
那我今天用到的 "延遲 和 取消延遲"也是一種定時器,應該屬於"timer sources(定時器) "類型的"源事件".所以也要在當前線程的Run loop里面處理這個問題
描述一下,我使用 延遲 和取消延遲的使用場景:
在播放視頻的過程中, 點擊屏幕時候 要展示菜單,如果無其他操作,菜單自動消失,如果是再單點擊屏幕則菜單被手動觸發消失.
那么在整個交互邏輯的過程中,從展示菜單那一刻起,添加 "延遲方法" ,如果是單點屏幕取消菜單,則要"取消延遲".
代碼如下:
[self performSelector:@selector(onClickOverlay:) withObject:nil afterDelay:DelayTimeSeconds];
//延遲
[NSObject cancelPreviousPerformRequestsWithTarget:self]; //這個是取消當前run loop 里面所有未執行的 延遲方法(Selector Sources)
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onClickOverlay:) object:nil];// @selector 和 object 都和 延遲一致 就是 指定取消 未執行的一條或者多條的延遲方法.
參考文章
iOS 官方 runloop (先看這個 最重要)
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
認識runloop
http://www.jianshu.com/p/613916eea37f
runloop 詳解
http://blog.csdn.net/ztp800201/article/details/9240913