早期我們使用延時執行的方法都是用NSObject 類提供的,performSelector:系列的方法,具體有哪些我們看一下
我們一般讓某個對象延時執行某個方法都會調用包含 afterDelay這個參數的方法,此參數即代表延時多長時間執行 ,但是這一系列的方法的參數都只接受繼承自NSObject類得對象,也就是說如果我們要向其中傳入基本的數據類型,那就必須涉及到數據類型轉換,這顯然會增加開銷,而且這一系列的方法最多也就能傳如一個參數,如果我們要傳多個參數怎么辦呢 ,如果想繼續使用這個方法,那我們就必須把多個參數寫入數組或字典中去,然后把數組或字典對象傳給這個方法,那么着就又會增加我們插入數組或字典,解析數組或字典的代碼 ,數據量達到一定情況的話,這個開銷是可想而知的,而且我們還要知道數組和字典中得每個對象都代表什么,很麻煩;
不過我們可以用塊來解決這一問題 ,GCD 為我們提供了一個演示執行的塊函數,其具體定義如下:
void dispatch_after ( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block );
我們在調用此方法的時候,系統也考慮的很周到,當我們寫入dispatch_after時,這個完整的函數就會呈現出來,我們看一下
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });
調用很方便,如果我們想把里面的內容放到主線程中去運行的話,也很方便,例如:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [son study]; }); });
還記得當時有一個問題,就是想給UIButton的點擊事件加點料,讓系統中的所有的按鈕都禁止快速點擊或者連擊,當時問了看了好多博客,都沒有好的解決方案,前篇一律的討論或者建議,都是使用performSelector:afterDelay這種方法,但是這樣的話,我還要實現另一個方法 。后來是這么解決的呢 ,這里再次引用我之前寫的內容,重寫父類函數,然后使用GCD的dispatch_after 方法解決;
具體實現如下:
// // CommonButton.h // CommonButton // // Created by pk on 14/12/24. // Copyright (c) 2014年 pk. All rights reserved. // #import <UIKit/UIKit.h> @interface CommonButton : UIButton @end
// // CommonButton.m // CommonButton // // Created by pk on 14/12/24. // Copyright (c) 2014年 pk. All rights reserved. // #import "CommonButton.h" @implementation CommonButton /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { [super sendAction:action to:target forEvent:event]; self.enabled = NO; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.enabled = YES; }); } @end
這樣的實現,很清楚,結構簡明,使用簡單,想使用此方法,只要將改一下類得繼承就行;
總結:performSelector 系列方法所能處理的選擇器太過於局限性了 ,選擇器的返回值類型和參數的個數都會受到限制;
而dispatch_after就沒有這些問題,另外,如果想把任務放在另一個線程上執行,最好不要用performSelector系列方法,而應該把任務封裝到塊里,然后調用GCD的相關方法來實現就行