Skip to content

Instantly share code, notes, and snippets.

@mattwymore
Forked from couchdeveloper/RXTimer.h
Created November 14, 2015 23:28
Show Gist options
  • Save mattwymore/5a7c1aa611b68fd32668 to your computer and use it in GitHub Desktop.
Save mattwymore/5a7c1aa611b68fd32668 to your computer and use it in GitHub Desktop.
A timer based on dispatch_source_create() Objective-C
//
// RXTimer.h
//
// Copyright 2013 Andreas Grosam
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import <Foundation/Foundation.h>
@class RXTimer;
typedef void (^RXTimerHandler)(RXTimer* timer);
@interface RXTimer : NSObject
/**
Initializes a cancelable, one-shot timer in suspended state.
@discussion Setting a tolerance for a timer allows the system to fire later than the
scheduled fire date. This allows the system to optimize for increased power savings
and maintaining responsiveness. The timer may fire at any time between its scheduled
fire date and the scheduled fire date plus the tolerance. The timer will not fire before
the scheduled fire date, though. The default value is zero, which means no additional
tolerance is applied - however, the system may choose to set a minimal "leeway" value.
As the user of the timer, you will have the best idea of what an acceptable tolerance
for a timer will be. As a general rule of thumb, you should set the "tolerance" as large
as possible. This might be for example the minimal perceivable duration or delay for a
human user, say 50 ms. Your mileage may vary, but even a small amount of tolerance will
have a significant positive impact on the power usage of your application.
@param: delay The delay in seconds after the timer will fire
@param queue The queue on which to submit the block.
@param block The block to submit. This parameter cannot be NULL.
@param tolearance A tolerance in seconds the fire data can deviate. Must be
positive.
@return An initialized \p RXTimer object.
*/
- (id)initWithTimeIntervalSinceNow:(NSTimeInterval)delay
tolorance:(double)tolerance
queue:(dispatch_queue_t)queue
block:(RXTimerHandler)block;
/**
Starts the timer.
The timer fires once after the specified delay plus the specified tolerance.
*/
- (void) start;
/**
Cancels the timer.
The timer becomes invalid and its block will not be executed.
*/
- (void)cancel;
/**
Returns YES if the timer has not yet been fired and it is not cancelled.
*/
- (BOOL)isValid;
@end
//
// RXTimer.m
//
// Copyright 2013 Andreas Grosam
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "RXTimer.h"
#import <dispatch/dispatch.h>
@interface RXTimer ()
@end
@implementation RXTimer {
dispatch_source_t _timer;
uint64_t _interval;
uint64_t _leeway;
}
- (id) initWithTimeIntervalSinceNow:(NSTimeInterval)delay
tolorance:(double)tolerance
queue:(dispatch_queue_t)queue
block:(RXTimerHandler)block;
{
self = [super init];
if (self) {
_interval = delay * NSEC_PER_SEC;
_leeway = tolerance * NSEC_PER_SEC;
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_event_handler(_timer, ^{
dispatch_source_cancel(_timer); // one shot timer
if (block) {
block(self);
}
});
}
return self;
}
- (void) dealloc {
dispatch_source_cancel(_timer);
//dispatch_release(_timer);
}
// Invoking this method has no effect if the timer source has already been canceled.
- (void) start {
assert(_timer);
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, _interval),
DISPATCH_TIME_FOREVER /*one shot*/, _leeway);
dispatch_resume(_timer);
}
- (void) cancel {
dispatch_source_cancel(_timer);
}
- (BOOL) isValid {
return _timer && 0 == dispatch_source_testcancel(_timer);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment