Objective - C 底层

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];
上一篇下一篇

猜你喜欢

热点阅读