123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- //
- // WLButtonCountdownManager.m
- // WLButtonCountingDownDemo
- //
- // Created by wayne on 16/1/14.
- // Copyright © 2016年 ZHWAYNE. All rights reserved.
- //
- #import "WLButtonCountdownManager.h"
- #import <UIKit/UIKit.h>
- @interface WLCountdownTask : NSOperation
- /**
- * 计时中回调
- */
- @property (copy, nonatomic) void (^countingDownBlcok)(NSTimeInterval timeInterval);
- /**
- * 计时结束后回调
- */
- @property (copy, nonatomic) void (^finishedBlcok)(NSTimeInterval timeInterval);
- /**
- * 计时剩余时间
- */
- @property (assign, atomic) NSTimeInterval leftTimeInterval;
- /**
- * 后台任务标识,确保程序进入后台依然能够计时
- */
- @property (assign, nonatomic) UIBackgroundTaskIdentifier taskIdentifier;
- /**
- * `NSOperation`的`name`属性只在iOS8+中存在,这里定义一个属性,用来兼容 iOS 7
- */
- #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
- @property (copy) NSString *name;
- #endif
- @end
- @implementation WLCountdownTask
- #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
- @synthesize name;
- #endif
- - (void)dealloc {
- _countingDownBlcok = nil;
- _finishedBlcok = nil;
- }
- - (void)main {
-
- self.taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
-
- do {
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (self.countingDownBlcok) self.countingDownBlcok(self.leftTimeInterval);
- });
-
- [NSThread sleepForTimeInterval:1];
- } while (--self.leftTimeInterval > 0);
-
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (self.finishedBlcok) {
- self.finishedBlcok(0);
- }
- });
-
- if (self.taskIdentifier != UIBackgroundTaskInvalid) {
- [[UIApplication sharedApplication] endBackgroundTask:self.taskIdentifier];
- self.taskIdentifier = UIBackgroundTaskInvalid;
- }
- }
- @end
- @interface WLButtonCountdownManager ()
- @property (nonatomic, strong) NSOperationQueue *pool;
- @end
- @implementation WLButtonCountdownManager
- + (instancetype)defaultManager {
- static id instance = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- instance = [[self _alloc] _init];
- });
-
- if ([instance class] != [WLButtonCountdownManager class]) {
- NSCAssert(NO, @"该类不允许被继承");
- }
-
- return instance;
- }
- + (instancetype)alloc {
- NSCAssert(NO, @"请使用`+defaultManager`方法获取实例");
- return nil;
- }
- + (instancetype)allocWithZone:(struct _NSZone *)zone {
- NSCAssert(NO, @"请使用`+defaultManager`方法获取实例");
- return nil;
- }
- + (instancetype)_alloc {
- return [super allocWithZone:NSDefaultMallocZone()];
- }
- - (instancetype)init {
- NSCAssert(NO, @"请使用`+defaultManager`方法获取实例");
- return nil;
- }
- - (instancetype)_init {
- if (self = [super init]) {
- _pool = [[NSOperationQueue alloc] init];
- }
-
- return self;
- }
- - (void)scheduledCountDownWithKey:(NSString *)aKey
- timeInterval:(NSTimeInterval)timeInterval
- countingDown:(void (^)(NSTimeInterval))countingDown
- finished:(void (^)(NSTimeInterval))finished
- {
- if (timeInterval > 120) {
- NSCAssert(NO, @"受操作系统后台时间限制,倒计时时间规定不得大于 120 秒.");
- }
-
- if (_pool.operations.count >= 20) // 最多 20 个并发线程
- return;
-
- WLCountdownTask *task = nil;
- if ([self countdownTaskExistWithKey:aKey task:&task]) {
- task.countingDownBlcok = countingDown;
- task.finishedBlcok = finished;
- if (countingDown && task.leftTimeInterval > 0) {
- countingDown(task.leftTimeInterval);
- }
- } else {
- task = [[WLCountdownTask alloc] init];
- task.leftTimeInterval = timeInterval;
- task.countingDownBlcok = countingDown;
- task.finishedBlcok = finished;
-
- task.name = aKey;
-
- [_pool addOperation:task];
- }
- }
- - (BOOL)countdownTaskExistWithKey:(NSString *)akey
- task:(WLCountdownTask *__autoreleasing _Nullable *)task
- {
- __block BOOL taskExist = NO;
-
- [_pool.operations enumerateObjectsUsingBlock:^(__kindof WLCountdownTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- if ([obj.name isEqualToString:akey]) {
- if (task) *task = obj;
- taskExist = YES;
- *stop = YES;
- }
- }];
-
- return taskExist;
- }
- @end
|