UIButton+CountDown.h
#import <UIKit/UIKit.h>
typedef void(^RunBlock)(UIButton *button, NSInteger totalTime, NSInteger leftTime);
typedef void(^EndBlock)(UIButton *button);
@interface UIButton (CountDown)
/**
* 倒計時按鈕
*
* @param duration 總時間
* @param runBlock 倒計時期間回調
* @param endBlock 倒計時結束回調
*/
- (void)startWithDuration:(NSInteger)duration
running:(RunBlock)runBlock
finished:(EndBlock)endBlock;
@end
UIButton+CountDown.m
#import "UIButton+CountDown.h"
@implementation UIButton (CountDown)
- (void)startWithDuration:(NSInteger)duration running:(RunBlock)runBlock finished:(EndBlock)endBlock
{
__block NSInteger timeOut = duration;
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_async(dispatch_get_main_queue(), ^{
endBlock(self);
});
} else {
int allTime = (int)duration + 1;
int seconds = timeOut % allTime;
dispatch_async(dispatch_get_main_queue(), ^{
runBlock(self, duration, seconds);
});
timeOut--;
}
});
dispatch_resume(_timer);
}
@end
Tips:
倒計時除了GCD還可以使用NSTimer實現,但是有一個問題,也是我的測試反饋的:
應用進入後臺一段時間,倒計時不工作,它只會從上一次消失的時間開始繼續工作。
朋友們可以搜索“NSTimer 進入後臺”,網上是說:進入後臺,定時器線程被掛起,進入前臺才繼續工作。
所以,如果你有這方面的需求,而且是在不影響其他工作(比如音視頻播放),可以在 AppDelegate.m 中添加如下代碼:
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
__block UIBackgroundTaskIdentifier backgroundTask;
backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTask != UIBackgroundTaskInvalid)
{
backgroundTask = UIBackgroundTaskInvalid;
}
});
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTask != UIBackgroundTaskInvalid)
{
backgroundTask = UIBackgroundTaskInvalid;
}
});
});
}
參考文章: