YYTimer的学习

YYTimer的学习_第1张图片
图片来之网络

定时器用了那么多年,从来没有想过如何自己实现,除了for循环加上线程的sleep,没有想到更好的方法。等看到代码

__weak typeof(self) _self = self;
    _lock = dispatch_semaphore_create(1);
    _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);
    dispatch_source_set_event_handler(_source, ^{[_self fire];});
    dispatch_resume(_source);

才明白,多线程那么古老的实现啊。

信号量

代码中_lock = dispatch_semaphore_create(1);是使用了信号量semaphore。
在GCD中有三个函数是semaphore的操作,分别是:

  • dispatch_semaphore_create   创建一个semaphore
  • dispatch_semaphore_signal   发送一个信号
  • dispatch_semaphore_wait    等待信号
- (void)dispatch
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    for (int i = 0; i < 100; i++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_group_async(group, queue, ^{
            NSLog(@"i is %i", i);
            sleep(2);

            dispatch_semaphore_signal(semaphore);
        });
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"结果");
}

创建一个初始值为10的semaphore,可以实现最多并发上限为10. 使用dispatch_semaphore_wait方法来阻止并发,如果信号量的值为0则一直等待。

  • 调用dispatch_semaphore_wait时表示,需要使用资源,semaphore的value 减一。
  • 调用dispatch_semaphore_signal时表示,需要放放资源,semaphore的value加以。
  • 所以这2个方法的调用需要成对出现,不然会导致线程被无限的阻塞。

dispatch源

_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());

创建一个定时器的dispatch源,DISPATCH_SOURCE_TYPE_TIMER为定时器类型。

定时器

dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);

创建一个定时器,设置第一次触发的时间,间隔时间。

dispatch_source_set_event_handler(_source, ^{[_self fire];});

设置响应dispatch源事件的block,在分派源指定的队列上运行.

dispatch_resume(_source);

在dispatch源创建后默认是挂起的,需要用dispatch_resume函数来恢复监听。
定时器就创建完成了,主要使用GCD提供的方法来实现。

保证定时任务每次执行一条

- (void)invalidate {
    dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
    if (_valid) {
        dispatch_source_cancel(_source);
        _source = NULL;
        _target = nil;
        _valid = NO;
    }
    dispatch_semaphore_signal(_lock);
}

- (void)fire {
    if (!_valid) return;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
    id target = _target;
    if (!target) {
        dispatch_semaphore_signal(_lock);
        [self invalidate];
    } else {
        dispatch_semaphore_signal(_lock);
        [target performSelector:_selector withObject:self];
        if (!_repeats) {
            [self invalidate];
        }
    }
#pragma clang diagnostic pop
}

每次调用方法由定时器触发。因为semaphore初始化值为1,所以资源最多为1,保证每次只能执行一条。

// END

你可能感兴趣的:(YYTimer的学习)