開(kāi)篇
很喜歡某個(gè)游戲英雄的一句臺(tái)詞“時(shí)間不在于你擁有多少筛峭,而在于你怎樣使用”铐刘。今天我們就來(lái)介紹一下時(shí)間的使用方式定時(shí)器,死板的定理向來(lái)不是我的風(fēng)格今天我們就通過(guò)一個(gè)例子為開(kāi)頭來(lái)說(shuō)明一下定時(shí)的使用影晓,但絕不僅僅于此镰吵。
上面兩張圖展示的就是一個(gè)注冊(cè)賬號(hào)時(shí)發(fā)生手機(jī)短信驗(yàn)證碼的界面,而獲取驗(yàn)證碼的倒計(jì)時(shí)就是用的定時(shí)器來(lái)實(shí)現(xiàn)的挂签。
定時(shí)器簡(jiǎn)單實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)
為了能夠很好的演示疤祭,我們新建一個(gè)工程用來(lái)顯示我們的倒計(jì)時(shí)功能。如下圖所示饵婆,我們先創(chuàng)建兩個(gè)按鈕勺馆,分別用來(lái)出發(fā)倒計(jì)時(shí)的事件。
- 屬性的設(shè)置
@interface ViewController ()
{
NSInteger _count;
}
@property(nonatomic,strong)UIButton *PushBtn;
@property(nonatomic,strong)UIButton *NSTimerbtn;
@property(nonatomic,strong)UIButton *GCDbtn;
/** 定時(shí)器(這里不用帶*侨核,因?yàn)閐ispatch_source_t就是個(gè)類(lèi)草穆,內(nèi)部已經(jīng)包含了*) */
@property (nonatomic, strong) dispatch_source_t timer;
- NSTimer 按鈕點(diǎn)擊事件中
self.NSTimerbtn.enabled =NO; //禁止點(diǎn)擊
_count = 60;
[self.NSTimerbtn setTitle:@"60秒" forState:UIControlStateDisabled];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
- 定時(shí)器事件
-(void)timerFired:(NSTimer *)timer
{
if (_count !=1) {
_count -=1;
[self.NSTimerbtn setTitle:[NSString stringWithFormat:@"%ld秒",_count] forState:UIControlStateDisabled];
}
else
{
[timer invalidate]; //定時(shí)器停止
self.NSTimerbtn.enabled = YES;
[self.NSTimerbtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[self.NSTimerbtn setTitle:@"獲取驗(yàn)證碼" forState:UIControlStateNormal];
}
}
這樣基本上就實(shí)現(xiàn)了簡(jiǎn)單的倒計(jì)時(shí),運(yùn)用的方法是NSTimer定時(shí)器搓译。從上面的圖中可以看到悲柱,還有一個(gè)GCD定時(shí)器的用法。
- GCD定時(shí)器實(shí)現(xiàn)倒計(jì)時(shí)
__block int count = 10;
// 獲得隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
// 創(chuàng)建一個(gè)定時(shí)器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 設(shè)置定時(shí)器的各種屬性(幾時(shí)開(kāi)始任務(wù)些己,每隔多長(zhǎng)時(shí)間執(zhí)行一次)
// GCD的時(shí)間參數(shù)豌鸡,一般是納秒(1秒 == 10的9次方納秒)
// 何時(shí)開(kāi)始執(zhí)行第一個(gè)任務(wù)
// dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比當(dāng)前時(shí)間晚3秒
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
// 設(shè)置回調(diào)
dispatch_source_set_event_handler(self.timer, ^{
count = count - 1;
[self.GCDbtn setTitle:[NSString stringWithFormat:@"%d秒",count] forState:UIControlStateNormal];
self.GCDbtn.enabled = NO;
[self.GCDbtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
if (count == 0) {
// 取消定時(shí)器
dispatch_cancel(self.timer);
self.timer = nil;
self.GCDbtn.enabled = YES;
[self.GCDbtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[self.GCDbtn setTitle:@"獲取驗(yàn)證碼" forState:UIControlStateNormal];
}
});
// 啟動(dòng)定時(shí)器
dispatch_resume(self.timer);
上述兩種方法都可以實(shí)現(xiàn)倒計(jì)時(shí)的功能,如下圖
真正的開(kāi)始
我們是使用了NSTimer和GCD實(shí)現(xiàn)了倒計(jì)時(shí)段标,但是對(duì)它們的了解到底有多深呢涯冠。面對(duì)GCD和NSTimer我們要選擇哪種方式呢。要想做出選擇首先我們要對(duì)他們有一定的了解然后才能誰(shuí)才是適合我們的逼庞。
如果選擇GCD
如果說(shuō)選擇了GCD定時(shí)器蛇更,像上面那樣寫(xiě)一個(gè)也就可以忍,但是如果用到多個(gè)定時(shí)器的話,每次都要寫(xiě)很多械荷,實(shí)在太累了共耍,就想封裝一個(gè),但是我寫(xiě)好之后吨瞎,看到另一篇簡(jiǎn)書(shū)的內(nèi)容痹兜,人家已經(jīng)封裝了,而且竟然比我封裝的還全面(-_-`)颤诀,這里就不放我自己的了字旭,放個(gè)傳送門(mén)吧(哈哈)GCD定時(shí)器封裝的代碼
具體的用法作者講的比較清楚,這里在說(shuō)一下崖叫,怎么用這個(gè)封裝的定時(shí)器來(lái)實(shí)現(xiàn)倒計(jì)時(shí)驗(yàn)證碼遗淳。首先在按鈕的點(diǎn)擊事件里,加入倒計(jì)時(shí)心傀,然后實(shí)現(xiàn)倒計(jì)時(shí)里的方法屈暗。
[[JX_GCDTimerManager sharedInstance]cancelTimerWithName:@"mytimers"];
__weak typeof(self) weakSelf = self;
[[JX_GCDTimerManager sharedInstance]scheduledDispatchTimerWithName:@"mytimers" timeInterval:1 queue:nil
repeats:YES actionOption:AbandonPreviousAction action:^{
[weakSelf dosomthing];
下一步實(shí)現(xiàn) [weakSelf dosomthing]方法,從而完成點(diǎn)擊按鈕顯示數(shù)字脂男。這里需要注意的就是UI的刷新必須回到主線程养叛,因?yàn)橛?jì)數(shù)是在子線程里可以完成的,但是UI的刷新如果不回到主線程是不會(huì)刷新的宰翅,你會(huì)誤以為定時(shí)器無(wú)效弃甥,然而并不是。
-(void)dosomthing{
__weak typeof(self) weakSelf = self;
_count = _count - 1;
NSLog(@"%ld",_count);
dispatch_sync(dispatch_get_main_queue(), ^{
weakSelf.GCDbtn.enabled = NO;
[weakSelf.GCDbtn setTitle:[NSString stringWithFormat:@"%ld秒",_count] forState:UIControlStateNormal];
[weakSelf.GCDbtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
});
if (_count< 1) {
[[JX_GCDTimerManager sharedInstance] cancelTimerWithName:@"mytimers"];
weakSelf.GCDbtn.enabled = YES;
[weakSelf.GCDbtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[weakSelf.GCDbtn setTitle:@"獲取驗(yàn)證碼" forState:UIControlStateNormal];
_count = 10;
}
}
這樣我們就實(shí)現(xiàn)了用封裝的GCD定時(shí)器實(shí)現(xiàn)的倒計(jì)時(shí)方法汁讼。自己把GCD定時(shí)器封裝起來(lái)還是有很多好處的淆攻,用GCD定時(shí)器相對(duì)于NSTimer可以幫我們減少內(nèi)存泄漏的風(fēng)險(xiǎn),同時(shí)GCD還可以幫我們處理線程級(jí)的邏輯嘿架。有了封裝的定時(shí)器我們就可以隨心所欲的使用了啊瓶珊。
如果選擇NSTimer
NSTimer用起來(lái)也只是簡(jiǎn)單的使用,對(duì)他的認(rèn)識(shí)也確實(shí)不夠深入耸彪,這里就推薦一篇個(gè)人認(rèn)為比較好的文章吧伞芹,反正我看了之后是學(xué)習(xí)良多,感慨iOS要學(xué)習(xí)的地方還很多啊搜囱。奉上博客原文:NSTimer你真的會(huì)用了嗎
- NSTimer不是一種實(shí)時(shí)的機(jī)制丑瞧,會(huì)存在延遲柑土,而且延遲的程度跟當(dāng)前線程的執(zhí)行情況有關(guān)蜀肘。會(huì)因?yàn)楫?dāng)前線程的堵塞導(dǎo)致延時(shí)。
- 必須得把timer添加到runloop中稽屏,它才會(huì)生效扮宠。
- 要讓timer生效,必須保證該線程的runloop已啟動(dòng),而且其運(yùn)行的runloopmode也要匹配坛增。
后記
關(guān)于定時(shí)器的這里就先說(shuō)到這么多获雕,有自己使用的也有自己學(xué)到的,感覺(jué)要學(xué)習(xí)的還很多收捣,有許多博客和文章確實(shí)能學(xué)到許多東西届案,比如,文中舉例的兩篇文章罢艾,都講解的比較深入楣颠,器這里權(quán)且當(dāng)做是拋磚引玉吧。