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];
}];