Objective - C 内存管理(二)GCD定时器
2020-04-13 本文已影响0人
爱玩游戏的iOS菜鸟
GCD定时器的使用场景
NSTimer
依赖于RunLoop
,如果RunLoop的任务过于繁重,可能会导致NSTimer不准时,而GCD的定时器会更加准时
//需要持有,定时器才会走
@property(nonatomic,strong) dispatch_source_t timer;
//主线程
dispatch_queue_t queue = dispatch_get_main_queue();
//子线程
//dispatch_queue_t queue = dispatch_queue_create( "timeQueue", DISPATCH_QUEUE_SERIAL);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
NSTimeInterval start = 5.0;//2秒后执行
NSTimeInterval interval = 1.0;//间隔1秒执行
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(start* NSEC_PER_SEC)), interval * NSEC_PER_SEC, 0);
NSLog(@"start");
//设置回调
//第一种方式 block
dispatch_source_set_event_handler(timer, ^{
NSLog(@"11111");
});
//第二种方式 传入函数
//dispatch_source_set_event_handler_f(timer, timeAction);
dispatch_resume(timer);
self.timer = timer;
/*
void timeAction(void *param)
{
NSLog(@"11111 %@",[NSThread currentThread]);
}
*/
1.如果需要将定时器放在子线程中,则更换主队列为创建的队列即可
2.GCD创建的对象(dispatch_queue_t 、dispatch_source_t)在ARC环境下,是不需要去销毁的
下面尝试封装一下定时器方法:
@interface ZQTimer : NSObject
//闭包
+ (NSString *)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;
//target selector
+ (NSString *)execTaskWithTarget:(id)target selector:(SEL)selector start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;
+ (void)cancelTask:(NSString *)task;
@end
//ZQTimer.m
@implementation ZQTimer
static NSMutableDictionary *timers_;
static dispatch_semaphore_t semaphore_;
+ (void)initialize{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
timers_ = [NSMutableDictionary dictionary];
semaphore_ = dispatch_semaphore_create(1);
});
}
+ (NSString *)execTask:(void (^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async{
if (!task || start < 0 || (repeats && interval <= 0)) return nil;
//队列
dispatch_queue_t queue = async ? dispatch_queue_create( "timeQueue", DISPATCH_QUEUE_SERIAL) : dispatch_get_main_queue();
//创建定时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//设置时间
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(start* NSEC_PER_SEC)), interval * NSEC_PER_SEC, 0);
//对下面对字典的操作进行加锁
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
//定时器的唯一标识
NSString *name = [NSString stringWithFormat:@"%ld",timers_.count];
//存放到字典中
timers_[name] = timer;
dispatch_semaphore_signal(semaphore_);
//设置回调
dispatch_source_set_event_handler(timer, ^{
task();
if (!repeats) {//不重复的任务
[self cancelTask:name];
}
});
//启动定时器
dispatch_resume(timer);
return name;
}
+ (NSString *)execTaskWithTarget:(id)target selector:(SEL)selector start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async{
if (!target || !selector) return nil;
return [self execTask:^{
if ([target respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[target performSelector:selector];
#pragma clang diagnostic pop
}
} start:start interval:interval repeats:repeats async:async];
}
+ (void)cancelTask:(NSString *)task{
if (task.length == 0) return;
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
dispatch_source_t timer = timers_[task];
if (!timer) return;
dispatch_source_cancel(timers_[task]);
[timers_ removeObjectForKey:@"name"];
dispatch_semaphore_signal(semaphore_);
}
@end
调用代码:
[ZQTimer execTask:^{
NSLog(@"111 %@",[NSThread currentThread]);
} start:2.0 interval:1.0 repeats:YES async:YES];