読者です 読者をやめる 読者になる 読者になる

dispatchのcancelの方法を実践してみる

別スレッドでタイマーなど処理を行いたい場合にカーネルに登録できるGCDを使用できます。
このGCDはキャンセルもできるのですが、
今回は、他のクラスからcancelをしたいと思ったのでそのような書き方をしています。
正しい書き方かは分かりませんが、備忘録として残しておきます。

@implementation HogehogeClass

//staticにして、Cancelできるようにしておく
static dispatch_source_t _source;

+ (void)setTimer:(NSDate *)date block:(void(^)(void))block{
    //deltaIntervalを取得して渡してあげる
    NSTimeInterval deltaInterval = [date timeIntervalSinceDate:[NSDate date]];
    [self asyncAfterDelay:deltaInterval  block:block];
}

+ (void)asyncAfterDelay:(NSTimeInterval)delay block:(void(^)(void))block {
    return [self asyncAfterDate:[NSDate dateWithTimeIntervalSinceNow:delay] block:block];
}

+ (void)asyncAfterDate:(NSDate *)date block:(void(^)(void))block {
    __block dispatch_queue_t _queue = dispatch_queue_create("jp.co.hoge.HogeHoge", NULL);
    //staticで宣言しておいたもの
    _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _queue);
    dispatch_source_set_event_handler(_source, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            //時間になったら呼ばれるもの
            block();
            //呼ばれたら処理をキャンセルします
            if (_source) {
                dispatch_source_cancel(_source);
            }
        });
    });
    dispatch_time_t delta = getDispatchTimeByDate(date);
    dispatch_source_set_timer(_source, delta, NSEC_PER_SEC, 0);
    dispatch_resume(_source);
}

//ここのClassを呼ぶ事で実行中の処理をCancelできます。
+ (void)cancelTimer {
    if (_source) {
        dispatch_source_cancel(_source);
    }
}

dispatch_time_t getDispatchTimeByDate(NSDate *date) {
    NSTimeInterval interval;
    double second, subsecond;
    struct timespec time;
    dispatch_time_t milestone;
    interval = [date timeIntervalSince1970];
    subsecond = modf(interval, &second);
    time.tv_sec = second;
    time.tv_nsec = subsecond * NSEC_PER_SEC;
    milestone = dispatch_walltime(&time, 0);
    return milestone;
}

@end
他のクラスでCancelしたいときはこのように呼ぶ
[HogehogeClass cancelTimer];
先ほどのタイマーをセットする
[HogehogeClass setTimer:セットしたい時間 block:^{
    //時間になったらやりたい処理。(blockで渡す)    
    [self XXXXX];
    }];