使用GCD封装一个简单的定时器

1、GCD定时器实现的基础代码

1
2
3
4
5
6
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
    <#code to be executed when timer fires#>
});
dispatch_resume(timer);

2、对其进行简单封装,使外部调用时传入间隔时间、重复次数、定时执行代码即可自动定时执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#import <Foundation/Foundation.h>
 
NS_ASSUME_NONNULL_BEGIN
 
@interface SATimer : NSObject
 
/**
 创建并开启一个定时任务
 
 @param interval 重复执行的间隔时间
 @param count 重复次数
 @param block 重复执行代码
 @return 返回定时器的唯一标识
 */
+ (NSString *)timerWithInterval:(NSTimeInterval)interval repeatCount:(NSUInteger)count block:(void (^)(NSUInteger remainCount))block;
 
/**
 根据定时器的唯一标识,停止定时器
 
 @param timerId 定时器唯一标识
 */
+ (void)invalidateWithId:(NSString *)timerId;
@end
 
NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#import "SATimer.h"
static NSMutableDictionary  *timerDictionary_;
static NSMutableDictionary  *countDictionary_;
static dispatch_semaphore_t semaphore_;
@implementation SATimer
+ (void)initialize
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        semaphore_ = dispatch_semaphore_create(1);
        timerDictionary_ = [NSMutableDictionary dictionary];
        countDictionary_ = [NSMutableDictionary dictionary];
    });
}
+ (NSString *)timerWithInterval:(NSTimeInterval)interval repeatCount:(NSUInteger)count block:(void (^)(NSUInteger remainCount))block;
{
    if ((block == nil) || (count <= 0) || (interval <= 0)) return nil;
    // gcd定时器基本实现
    dispatch_queue_t queue = dispatch_queue_create("com.yusian.timer-queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, interval * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    NSString *timerId = [NSString stringWithFormat:@"%p", timer];
 
    // 字典写入时的线程安全
    dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
    [timerDictionary_ setObject:timer forKey:timerId];
    [countDictionary_ setObject:@(count) forKey:timerId];
    dispatch_semaphore_signal(semaphore_);
    // 执行定时任务
    dispatch_source_set_event_handler(timer, ^{
        NSNumber *count = [countDictionary_ objectForKey:timerId];
        NSUInteger remainCount = count.unsignedIntegerValue;
        block(--remainCount);
        // 字典写入时的线程安全
        dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
        [countDictionary_ setObject:@(remainCount) forKey:timerId];
        dispatch_semaphore_signal(semaphore_);
        // 重复次数剩余量为0时自动退出
        if (remainCount == 0) [self invalidateWithId:timerId];
    });
    dispatch_resume(timer);
    return timerId;
}
 
+ (void)invalidateWithId:(NSString *)timerId
{
    dispatch_source_t timer = [timerDictionary_ objectForKey:timerId];
    if (timer == nil) return;
    dispatch_source_cancel(timer);
    [timerDictionary_ removeObjectForKey:timerId];
    [countDictionary_ removeObjectForKey:timerId];
    NSLog(@"SATimer invalidate - %@", timerId);
}
 
@end

Leave a Reply