YYTimer的学习

图片来之网络

定时器用了那么多年,从来没有想过如何自己实现,除了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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 2016年国庆假期终于把此书过完,整理笔记和体会于此。 关于书名 书名源于俄罗斯的演员斯坦尼斯拉夫斯基创作的《演员...
    李剑飞的简书阅读 12,042评论 2 65
  • 锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...
    LiLS阅读 5,415评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,403评论 19 139
  • 密雨若心,了然于你 ,丝丝缕缕,自然便落进焦渴的秘地里。花色正红,暑色郁浓,鲜妍的娇容唤你待至又朦,放肆的风雨却促...
    兰爱笔阅读 3,446评论 0 0
  • 开个头,简书相比较微信公众号或自己建的博客还是很容易上手的!
    静夜思_阅读 1,456评论 0 0