Home | About | Apps | Github | Rss
Dispatch souces define an event source that when triggered can invoke a pre-defined callback. Instead of registering for events and then writing logic to handle events to make a callback, dispatch source can be used.
Dispatch timer
For example, with interval timers, its not trivial to setup NSTimer outside of main threads as it requires a run-loop with predictable lifetime. Using a runloop outside main thread is painful. Dispatch queues have ephimeral threads and as such are bad candidates for use with NSTimers.
This is a scenario where dispatch source is an ideal use-case. A dispatch timer source, fires an event when the time interval has been completed, which then fires a pre-set callback all on the same queue.
// Define a queue
queue = dispatch_queue_create("com.blah",0);
// Define timer
interval_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// Configure timer with type(wallclock), interval(2 mins), leeway(5)
// leeway is acceptable error
dispatch_source_set_timer( interval_timer, dispatch_walltime(NULL,0), 2*60, 5 );
// Callback when timer is fired
dispatch_source_set_event_handler(interval_timer, ^{
NSLog(@"Timer event");
});
It is also easy to start and suspend timer events. Its as simple as calling
dispatch_resume( interval_timer );
dispatch_suspend( interval_timer );
Dispatch After
If an event needs to be fired after a time interval, but does not require cancellation, it is simpler to just use dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<delayInSeconds> * NSEC_PER_SEC)), <queue>, ^{
// code to be executed after a specified delay
});
Example: Flushing Queue after time interval
Here is some pseudo/sample code that consumes objects via -addEvent:
until - either the object count becomes <N>
, or <T>
seconds have elapsed since last object add and in the end calls -flush:
@implementation KCTimer
{
dispatch_source_t _interval_timer;
dispatch_queue_t _flush_queue;
NSUInteger _count;
NSUInteger _timelimit;
}
- (instancetype) initWithCount:(NSUInteger)count andTimeLimit:(NSUInteger)limit
{
if( self = [super init] ) {
_timelimit = limit;
_count = count;
_flush_queue = dispatch_queue_create("com.blah",0);
_interval_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, flush_queue);
dispatch_source_set_event_handler(_interval_timer, ^{
[self flush];
});
[self reset];
[self resume];
}
return self;
}
- (void)resume
{
dispatch_resume( _interval_timer );
}
- (void)suspend
{
dispatch_suspend( _interval_timer );
}
- (void)reset
{
dispatch_source_set_timer( interval_timer, dispatch_walltime(NULL,0), _timelimit, 5 );
}
- (void)addEvent:(Event *)e
{
// TODO: Add stuff in thread safe manner
[self reset];
if(eventCount >= 50) {
dispatch_async(flush_queue,^{
[self flush];
});
}
}
- (void)flush
{
// TODO: Flush queue in thread safe manner
}