Triggering a method at times stored in Array using NSTimer - ios

I have an Array that have stored times. I want NStimer to trigger at times stored in that array. For example, in array a[] i have 2, 5 and 10 seconds and want NSTimer to trigger a method at these times. I do have another NSTimer that keep updating the time instance variable every second.

A simple solution would be to loop through your array and schedule method calls with GCD
for (NSNumber *time in array) {
NSTimeInterval delay = [time doubleValue];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#code to be executed after a specified delay#>
});
}

Related

Synchronized countdown timer with `NSTimeInterval` without skipping seconds? (presumably due to rounding)

I was wondering if there was a clean way to do a countdown timer with Grand Central Dispatch (then display for example in a UILabel) that's synchronized to the system clock... based on a reference date? — So if my reference date is an NSDate that's 20 minutes from now, I'd have a countdown displayed in seconds (don't worry about formatting) that's synced to the system clock.
Just doing a quick version of this skips seconds every once in a while in case the update method call doesn't arrive on schedule.
To me this seems like a pretty basic question, so I'm looking ideally for a basic/clean solution besides increasing the update interval to be 10x or something.
Also, the solution shouldn't use NSTimer.
I would use a recursive method like this:
- (void) updateTimer{
NSDate *now = [NSDate date];
NSTimeInterval secondsToDate = [now timeIntervalSinceDate:self.referenceDate];
_timerLabel.text = [NSString stringWithFormat:#"%.0f", secondsToDate];
if( secondsToDate < 0 ){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self updateTimer];
});
}else{
NSLog(#"Timer triggered!");
}
}
You just have to call it the first time, then it will update the countdown every 0.1 seconds.

How to use block handler for getting return value when timer running in objective-c (IOS)

I have a timer that run on 10 minutes. I want to get time at the 5th minute for some actions before end time (the 10th minute). May be not use block handler if you have another better solution.
You can use "performSelector" to do whatever you want at the 5th minute.
NSTimeInterval duration = 10 * 600;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self func];
});

How to call a method after few seconds without affecting ui?

I am using tableview and I want to call a method after some time duration.This method return a array and reload the tableview.I want within this time duration UI doesn't stuck.
Best to use Grand Central Dispatch (GCD). If you call dispatch_after(), you can run a block of code whenever you want.
// Run this code after 1 second.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self someMethod];
});

Delay via GCD vs. sleep()

I have the method in which I need to make a 5 sec delay every time I call it. Firstly I make it with sleep(5); - it worked excellent but I believe - it's not obj-c way, so I tried to write it with GCD help. The first call of this procedure make a delay about 5 sec, but other calls in this queue are going one after one without delay. How to solve this problem?
- (void) buyItemAtUUID:(NSString*)UUID
{
dispatch_barrier_async(dataManagerQueue, ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dataManagerQueue, ^(void){
NSInteger path = [self indexFromObjectUUID:UUID];
if (path != NSNotFound)
{
NSMutableDictionary *item = [[_items objectAtIndex:path] mutableCopy];
NSNumber *value = [NSNumber numberWithFloat:[[item objectForKey:#"Quantity"] floatValue] - 1.0];
}
});
});
}
The first call of this procedure make a delay about 5 sec, but other
calls in this queue are going one after one without delay.
That's usually desired behavior. The reason you shouldn't call sleep() is that it'll block the thread, preventing anything else in that thread from happening. If you block the main thread, your device will appear to freeze, which isn't a very nice user experience.
GCD provides a nice dispatch_group_wait() function that lets you make one set of tasks wait for some other group to finish. Take a look at Waiting on Groups of Queued Tasks for an example.
dispatch_barrier_async only stops blocks added to the concurrent queue after this block from running. The blocks that were already queued are not prevented from running.

Proper way to delay while allowing the run loop to continue

I have a need to delay for a certain amount of time and yet allow other things on the same runloop to keep running. I have been using the following code to do this:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
This seems to do exactly what I want, except that sometimes the function returns immediately without waiting the desired time (1 second).
Can anyone let me know what could cause this? And what is the proper way to wait while allowing the run loop to run?
NOTE: I want to delay in a manner similar to sleep(), such that after the delay I am back in the same execution stream as before.
You should use GCD and dispatch_after for that. It is much more recent and efficient (and thread-safe and all), and very easy to use.
There is even a code snippet embedded in Xcode, so that if you start typing dispatch_after it will suggest the snippet and if you validate it will write the prepared 2-3 lines for you in your code :)
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
<#code to be executed on the main queue after delay#>
});
Use an NSTimer to fire off a call to some method after a certain delay.
Have you tried performSelector:withObject:afterDelay:?
From the Apple documentation
Invokes a method of the receiver on the current thread using the default mode after a delay.
I had a similar issue and this is my solution. Hope it works for others as well.
__block bool dispatched = false;
while ( put your loop condition here )
{
if (dispatched)
{
// We want to relinquish control if we are already dispatched on this iteration.
[ [ NSRunLoop currentRunLoop ] runMode: NSDefaultRunLoopMode beforeDate:[ NSDate date ] ];
continue;
}
// mark that a dispatch is being scheduled
dispatched = true;
int64_t delayInNanoSeconds = (int64_t) (0.1 * (float) NSEC_PER_SEC);
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, delayInNanoSeconds);
dispatch_after(delayTime, dispatch_get_main_queue(), ^() {
// Do your loop stuff here
// and now ready for the next dispatch
dispatched = false;
} );
} // end of while

Resources