ScottyB
ScottyB

Reputation: 2497

How to schedule iOS method call at exact time

I would like iOS to call my object's method at an exact time in the future. The time to call the method could be up to 4 hours from the current time.

I know I could use NSTimer, but I'm concerned it won't be precise enough for my application (i.e., within 30-50 ms): "A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed."

I've also seen mentions of using CADisplayLink for precision, but more in the context of interval timing.

Another alternative may be threading to avoid delays caused by the system run loop.

Which is considered "best" choice for what I want to do, or is there something else I should look at? Or is NSTimer precise enough if very little else is really going on in my app? Thanks!

Upvotes: 1

Views: 4835

Answers (4)

Buunk
Buunk

Reputation: 19

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            double delayInSeconds = 0.2; 
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self doTimer];
        });
});

- (void) doTimer {
  // your code 
}

Upvotes: 1

Harish Suthar
Harish Suthar

Reputation: 711

Well one better alternate to NSTimer is GCD you can use dispatch_after to call a method after some time, its even better.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // TO DO METHOD CALL.
});

Upvotes: 3

Sam
Sam

Reputation: 2579

NSTimer is definitely not the answer. If you want any kind of accuracy at all, I highly recommend you avoid NSTimer completely.

NSDate and will return an NSTimeInterval which is a double with sub ms accuracy. NSTimeInterval is in seconds, but it uses the double to give you greater precision.

Next on the chopping block is CoreAnimation with their function CFAbsoluteTimeGetCurrent. Many people think this is more precise than the previous options. It's not more accurate, or more precise. Also confusing is that this time function returns a value for system uptime. Since you're attempting to schedule something accurately, it would be pretty useless to you.

If you truly require greater precision, the only answer is mach_absolute_time. Take your time in understanding this class. This will return the time to you in processor dependent ticks. While it will require a bit of massaging to get back to wall time, since it's literally tracking CPU cycles, you CANNOT be more accurate than that.

Check out Apple's Tech Note on Precise Timing and Measurements.

EDIT: It seems like you want to run some code at a specified point in the future, the first and simplest solution that comes to my mind are UILocalNotifications. They handle timezones and tracking effortlessly, and since the fireDate is an NSDate you should see the same precision as another NSDate and vastly more accuracy than NSTimer.

Upvotes: 2

huong
huong

Reputation: 4564

I had the same problem with my last project and this is how I solved it. First, you need to save the time from when you start counting time. In my case, I chose to use NSDefault:

[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"ReminderStart"]

Then when you need to decide whether to call your method, you get the reminder start time from NSDefault, and use it to compare with the current time:

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *components = [gregorianCalendar components:NSMinuteCalendarUnit
                                                        fromDate:REMINDER_START_DATE
                                                          toDate:[NSDate date]
                                                         options:0];
if (components.minute > 30){
   //call your method here if the time difference is larger than 30 minutes
}

In my code I checked time difference in minutes, but you can totally adjust it to seconds, hours, days or weeks if you want. Hope that this helps.

Upvotes: 0

Related Questions