iOS開發——多線程完成短信獲取按鈕倒計時
現在的APP應用中,用手機獲取短信驗證碼是非常常見的一個功能,而往往要求的效果就是在按下獲取驗證碼之后,驗證碼的按鈕開始倒計時,例如30秒后重新獲取。而我們如何來完成這個效果呢,其實很簡單,用一個定時器來計時,設置定時器的時間為UIButton的Title,而這個步驟我們一般用多線程的定時器dispatch source來定時產生事件。
在網上看了別人寫的代碼,復用性比較差,沒有對這個方法進行良好的封裝,我在這里貼一段修改后的代碼,基本上大家黏貼過去就能復用。而后面我會解釋這個代碼的多線程方面的一些問題。
#pragma mark - 倒計時獲取驗證碼
-(void)changeTimeOut:(int)timeOut btnTag:(int)btnTag{
__block int timeout=timeOut;
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer=dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0*NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
if (timeout<=0) {
dispatch_source_cancel(_timer);
//dispatch_release(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//倒計時結束
_smsCodeBtn=(UIButton*)[self.view viewWithTag:[[NSString stringWithFormat:@"%d",btnTag] intValue]];
[_smsCodeBtn setTitle:@"重新獲取驗證碼" forState:UIControlStateNormal];
[_smsCodeBtn setUserInteractionEnabled:YES];
[_smsCodeBtn setTitleColor:[UIColor colorWithRed:53.0f/255.0f green:53.0f/255.0f blue:68.0f/255.0f alpha:1] forState:UIControlStateNormal];
[_smsCodeBtn.layer setBorderColor:[UIColor colorWithRed:53.0f/255.0f green:53.0f/255.0f blue:68.0f/255.0f alpha:1].CGColor];
});
}else{
NSString* strTime=[NSString stringWithFormat:@"%d秒后重新獲取",(int)(timeout)];
dispatch_async(dispatch_get_main_queue(), ^{
//倒計時
_smsCodeBtn=(UIButton*)[self.view viewWithTag:[[NSString stringWithFormat:@"%d",(int)btnTag] intValue]];
[_smsCodeBtn setTitle:strTime forState:UIControlStateNormal];
[_smsCodeBtn setTitleColor:[UIColor colorWithRed:153.0f/255.0f green:153.0f/255.0f blue:153.0f/255.0f alpha:1] forState:UIControlStateNormal];
[_smsCodeBtn.layer setBorderColor:[UIColor colorWithRed:153.0f/255.0f green:153.0f/255.0f blue:153.0f/255.0f alpha:1].CGColor];
[_smsCodeBtn setUserInteractionEnabled:NO];
});
timeout--;
}
});
dispatch_resume(_timer);
}
這段代碼中smsCodeBtn就是我定義的獲取短信驗證碼的UIButton,你們復制下去只要把frame屬性和ui屬性改一改,就完全可以直接用了。
那么接下來我們來講講這段代碼中多線程的問題。
首先我們先用 dispatch_get_global_queue 來開啟一個全局隊列,之后用 dispatch_source_t 來產生定時事件。所有定時器 dispatch_source 都是間隔定時器,一旦創建,會按你指定的間隔定期遞送事件。你需要為定時器 dispatch_source 指定一個期望的定時器事件精度,也就是leeway值,讓系統能夠靈活地管理電源并喚醒內核。例如系統可以使用leeway值來提前或延遲觸發定時器,使其更好地與其他系統事件結合。創建自己的定時器時,你應該盡量指定一個leeway值。
就算你指定的leeway值為0,也不要期望定時器能夠按照精確地納秒來觸發事件,系統會盡可能地滿足你的需求,但是無法保證完全精確的觸發時間。
如果你使用 dispatch_walltime 函數來設置定時器 dispatch_source ,則定時器會根據掛鐘時間來跟蹤,這種定時器比較適合觸發間隔相對比較大的場合,可以防止定時器觸發時間出現太大誤差。
dispatch_time 類型的時間我們可以通過 dispatch_time 來創建,也可以通過 dispatch_walltime 來創建。前者創建的時間多以第一個參數為參照物,之后過多久執行任務。后者多用于創建絕對時間,如某年某月某日某時某分執行某任務,比如鬧鐘的設置。
最后我們用 dispatch_source_set_event_handler 這個方法來創建我們要完成的任務,很簡單的語句,一個block閉包,里面的內容當然是自由發揮的咯。
所以交代清楚GCD中時間事件,這段代碼就非常容易理解了。
代碼很短也就不傳到Github上的demo了。如果有寫的不對的地方,歡迎交流。
來自:http://www.jianshu.com/p/bb42e5fc9886