Multiple action using selector after delay - iphone

Is there a way to do multiple actions respectively using the : performSelector:withObject:afterDelay code ?
Sample code will be appreciated ,
Thanks in advance.

Or use blocks. If you start to type dispatch_after, you'll see code completion that will pop up the following snippet of code, and then you can put however many actions you want in that block. In this example, I'm showing it being used inside an IBAction:
- (IBAction)pushedSomeButton:(id)sender
{
// anything you want to do immediate, do here
[self doingSomethingRightNow];
// anything you want to defer for some time, do inside the dispatch_after block
// in this example, calling callAnotherMethod and whyNotCallAnotherMethod
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){
[self callAnotherMethod];
[self whyNotCallAnotherMethod];
});
}

Setup a method that gets fired with the performSelector:withObject:afterDelay: call:
-(void)performTheseAction {
// do something
// do something else
[self callAnotherMethod];
[self whyNotCallAnotherMethod];
}

Related

Delay part of iPhone method

I have a method that takes several params, I need to delay a portion of that method. I DO NOT want to split it into several methods and use [self performSelectorAfterDelay] because the delay requires params already in that method. I need something like the following
-(void)someMethod{
.....
delay {
more code but not a separate self method
}
... finish method
}
The dispatch_after function seems to line up with what you need:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
// this code is going to be executed, on the main queue (or thread) after 2.0 seconds.
});
Of course, the time is configureable, and it's a bit confusing to read at first, but once you get used to how blocks work in conjunction with objective-c code, you should be good to go.
One word of caution:
NEVER, NEVER, NEVER! Block the main thread of an iPhone app using sleep(). Just don't do it!
Looks like an overkill.
-(void)someMethod{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSLog(#"Start code");
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_sync(backgroundQueue, ^{
sleep(5);
// delayed code
NSLog(#"Delayed code");
});
dispatch_sync(backgroundQueue, ^{
// finishing code
NSLog(#"Finishing code");
});
});
}
backgroundQueue might be user at external dispatch call. It looks really bad though :)

Need to implement timeout mechanism for UIRefreshControl.

Apple's new UIRefreshControl in iOS 6 is a welcome new feature, but it seems that there is no built-in timeout mechanism.
Here's the scenario why I need it:
Let's say the user pulls the refresh. It goes into the spinning mode, while the code tries to fetch data from the server. The server does not repond and will cause spinning wheel to spin forever. So, there should be a time out mechanism to stop it.
What's the best way to implement it?
First setup a timer with the amount of time you need. Ask it to check the following.
You can use the following property to check whether it is still refreshing after some time
#property (nonatomic, readonly, getter=isRefreshing) BOOL refreshing
If it is then you can stop it using
endRefreshing
Something like :
-(void)checkAndStop{
if(refreshControl.refreshing == YES)
// show an alert if you want
[refreshControl endRefreshing];
}
Also consider using dispatch_after, which might be less consumable than creating NSTimer.
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
});
I have implemented using NSTimer to end the refreshing:
[NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(handleDataRefreshFailure:) userInfo:nil repeats:NO];
Swift version:
let delayInSeconds: UInt64 = 2
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * NSEC_PER_SEC))
dispatch_after(popTime, dispatch_get_main_queue(), {
if refreshControl.refreshing {
refreshControl.endRefreshing()
}
})

How to call method with delay and in background thread

I have a method what I want to call after -viewDidLoad and in background thread. Is there way to combine this two methods:
[self performSelector:(SEL) withObject:(id) afterDelay:(NSTimeInterval)]
and
[self performSelectorInBackground:(SEL) withObject:(id)]?
Grand Central Dispatch has dispatch_after() which will execute a block after a specified time on a specified queue. If you create a background queue, you will have the functionality you desire.
dispatch_queue_t myBackgroundQ = dispatch_queue_create("com.romanHouse.backgroundDelay", NULL);
// Could also get a global queue; in this case, don't release it below.
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC);
dispatch_after(delay, myBackgroundQ, ^(void){
[self delayedMethodWithObject:someObject];
});
dispatch_release(myBackgroundQ);
Try the following:
// Run in the background, on the default priority queue
dispatch_async( dispatch_get_global_queue(0, 0), ^{
[self performSelector:(SEL) withObject:(id) afterDelay:(NSTimeInterval)]
});
Code not tested
Be aware that your selector/method must not use UIKit (so don't update the UI) or access UIKit properties (like frame) so your selector may need to kick off work back to the main thread. e.g.
(id)SomeMethod:UsingParams: {
// Do some work but the results
// Run in the background, on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
// Do something UIKit related
});
}
[self performSelector:(SEL) withObject:(id) afterDelay:(NSTimeInterval)]
Performs a selector on the thread that it is being called. So when you call it from a background thread it will run there...
You can do that per example:
dispatch_time_t delay = dispatch_time( DISPATCH_TIME_NOW, <delay in seconds> * NSEC_PER_SEC );
dispatch_after( delay, dispatch_get_main_queue(), ^{
[self performSelectorInBackground: <sel> withObject: <obj>]
});
Somehow a mixed solution. It would be better to stick with a full GCD approach tho.

How can I trigger a method every 10 seconds without using NSTimer?

I would like to call a method every 10 seconds, but I want to use something other than NSTimer. What could I use to do this?
I know you said you didn't want to use timers, but just to make sure you know how simple it would be with a timer...
[NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(someMethod)
userInfo:nil
repeats:YES];
If you dont want to use the timer, you can use GCD which internally will make use of NSOperationQueue, nevertheless will work in all cases. For eg: i had a class which was inherited from NSOperation so the above methods didn't work so i had go go with GCD:
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(popTime, queue, ^{
[self methodYouWantToCall];
});
The above code calls the method methodYouWantToCall after every three seconds.
You can create a loop with performSelector:withObject:afterDelay: setting afterDelay to 10.0.
I don't recommend this though, use an NSTimer.
- (void)callMeEvery10Seconds
{
[self performSelector:#selector(callMeEvery10Seconds)
withObject:nil
afterDelay:10.0];
// ... code comes here ...
}
If you are not using Cocos2D, you have to use a NSTimer to do this....
If you are using Cocos2D, use the schedule method
here's a link below that shows both :
How can I create a count down timer for cocos2d?
The easiest way to do so is:
- (void)scheduleLoopInSeconds:(NSTimeInterval)delayInSeconds
{
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(popTime, queue, ^{
[self callWhatEverMethodYouWant];
[self shceduleLoopcaInSeconds:delayInSeconds];//set next iteration
});
}
// now whenever you like call this, and it will be triggering "callWhatEverMethodYouWant" every 10 secs.
[self shceduleLoopcaInSeconds:10.0];

Blocks instead of performSelector:withObject:afterDelay: [duplicate]

This question already has answers here:
How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?
(20 answers)
Closed 9 years ago.
I often want to execute some code a few microseconds in the future. Right now, I solve it like this:
- (void)someMethod
{
// some code
}
And this:
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.1];
It works, but I have to create a new method every time. Is it possible to use blocks instead of this? Basically I'm looking for a method like:
[self performBlock:^{
// some code
} afterDelay:0.1];
That would be really useful to me.
There's no built-in way to do that, but it's not too bad to add via a category:
#implementation NSObject (PerformBlockAfterDelay)
- (void)performBlock:(void (^)(void))block
afterDelay:(NSTimeInterval)delay
{
block = [[block copy] autorelease];
[self performSelector:#selector(fireBlockAfterDelay:)
withObject:block
afterDelay:delay];
}
- (void)fireBlockAfterDelay:(void (^)(void))block {
block();
}
#end
Credit to Mike Ash for the basic implementation.
Here's a simple technique, based on GCD, that I'm using:
void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
dispatch_get_current_queue(), block);
}
I'm not a GCD expert, and I'd be interested in comments on this solution.
Another way (perhaps the worst way to do this for many reasons) is:
[UIView animateWithDuration:0.0 delay:5.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished) {
//do stuff here
}];
If you specifically need a longer delay, the solutions above work just fine. I've used #nick's approach with great success.
However, if you just want your block to run during the next iteration of the main loop, you can trim it down even further with just the following:
[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];
This is akin to using performSelector: with afterDelay of 0.0f
I used similar code like this:
double delayInSeconds = 0.2f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//whatever you wanted to do here...
});
There's a nice, complete category that handles this situation here:
https://gist.github.com/955123