Grand Central Dispatch 替代使用 NSTimer - 多次无效
Grand Central Dispatch alternative to using an NSTimer - invalidating multiple times
我在尝试使用 dispatch_source_t
时遇到问题。我想用它来延迟 PHChange
的处理 5 秒,因为 PHChange
可以在短时间内发生多次。如果能提供任何帮助,我将不胜感激。基本上我想取消之前的 dispatch_source_t
计时器,几乎就像 NSTimer
.
@property (nonatomic, strong) dispatch_source_t libraryChangedTimer;
dispatch_source_t CreateTimerDispatchSource(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
- (void)libraryChanged:(PHChange *)changeInstance
{
NSLog(@"Called immediately and it shouldn't");
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
if (self.libraryChangedTimer)
{
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
});
}
else
{
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
});
}
}
我使用 dispatch_after
代码非常简单地解决了这个问题:
dispatch_source_t CreateTimerDispatchSource(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), DISPATCH_TIME_FOREVER, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, interval), queue,^
{
dispatch_resume(timer);
});
}
return timer;
}
- (void)libraryChanged:(PHChange *)changeInstance
{
// Do something
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
if (self.libraryChangedTimer)
{
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = nil;
});
}
else
{
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = nil;
});
}
}
你的问题是这一行:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
您实际上是在指定 "now" 作为计时器的开始时间。这就是 dispatch_walltime(NULL, 0)
的计算结果。您将 interval
值作为计时器的间隔传递,这要求它在两次触发之间的那个时间段内重复。但是开始时间决定了第一次开火的时间。
你想要的是:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), interval, leeway);
或者,如果您实际上不想让计时器重复:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), DISPATCH_TIME_FOREVER, leeway);
我在尝试使用 dispatch_source_t
时遇到问题。我想用它来延迟 PHChange
的处理 5 秒,因为 PHChange
可以在短时间内发生多次。如果能提供任何帮助,我将不胜感激。基本上我想取消之前的 dispatch_source_t
计时器,几乎就像 NSTimer
.
@property (nonatomic, strong) dispatch_source_t libraryChangedTimer;
dispatch_source_t CreateTimerDispatchSource(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
- (void)libraryChanged:(PHChange *)changeInstance
{
NSLog(@"Called immediately and it shouldn't");
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
if (self.libraryChangedTimer)
{
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
});
}
else
{
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
});
}
}
我使用 dispatch_after
代码非常简单地解决了这个问题:
dispatch_source_t CreateTimerDispatchSource(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), DISPATCH_TIME_FOREVER, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, interval), queue,^
{
dispatch_resume(timer);
});
}
return timer;
}
- (void)libraryChanged:(PHChange *)changeInstance
{
// Do something
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
if (self.libraryChangedTimer)
{
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = nil;
});
}
else
{
self.libraryChangedTimer = CreateTimerDispatchSource(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
[self libraryChanged:changeInstance];
dispatch_source_cancel(self.libraryChangedTimer);
self.libraryChangedTimer = nil;
});
}
}
你的问题是这一行:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
您实际上是在指定 "now" 作为计时器的开始时间。这就是 dispatch_walltime(NULL, 0)
的计算结果。您将 interval
值作为计时器的间隔传递,这要求它在两次触发之间的那个时间段内重复。但是开始时间决定了第一次开火的时间。
你想要的是:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), interval, leeway);
或者,如果您实际上不想让计时器重复:
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), DISPATCH_TIME_FOREVER, leeway);