1

Calling [self presentViewController] on an instance of UIAlertController loads the alert immediately. Is there a way to delay its presentation?

[self presentViewController:alert animated:YES completion:nil];
Eric
  • 893
  • 10
  • 25

2 Answers2

5

You can use GCD or performSelector:withObject:afterDelay:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
     [self presentViewController:alert animated:YES completion:nil];
});

You can also create a local variable and then call present at the right time that you want. Depends on your use-case, one of these three should help you on delaying and showing the alert controller at the right moment.

EDIT: Here's the Swift version of this answer:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    self.present(alert, animated: true)
}

You can also check this answer

manman
  • 4,743
  • 3
  • 30
  • 42
  • The `performSelector:withObject:afterDelay:` doesn't work at all. GCD works but the alert from the UIAlertController is not appearing in the app. Is it because the alert should be called on the main thread? – Eric Oct 20 '15 at 21:21
  • Yes it should be called from the Main Thread otherwise you leave yourself open to weird / undefined behavior – darren102 Oct 20 '15 at 21:23
  • Yeah, make sure that your code is running on the main thread. I updated the code – manman Oct 20 '15 at 21:24
  • Does it make sense to encapsulate a call to an instance of a UIAlertController within GCD? – Eric Oct 20 '15 at 21:24
  • Yeah, you should be good depends on your reference type to the `UIViewController`. You can check http://stackoverflow.com/questions/20030873/always-pass-weak-reference-of-self-into-block-in-arc for in-detail of blocks and ARC – manman Oct 20 '15 at 21:27
  • Congratulations! You provide an excellent answer to my question. May everyone upvote the question and @manman's answer! – Eric Oct 20 '15 at 21:28
  • Great, glad it helped on your issue. – manman Oct 20 '15 at 21:29
  • Thanks once again . . . Do you know how to fine tune the delay? How can I change `(1 * NSEC_PER_SEC)` to speed things up just a little bit? – Eric Oct 20 '15 at 21:31
  • instead of 1, you should put the number of seconds that you want the delay. – manman Oct 20 '15 at 21:38
  • The call to `dispatch_async` is pointless here. As written, the call to `dispatch_after` already ensures its block is called on the main thread. – rmaddy Oct 20 '15 at 21:41
  • @rmaddy Without `dispatch_async` the UIAlert is not called. Which should I use `dispatch_after` or `dispatch_async`? – Eric Oct 20 '15 at 21:43
  • If I want a value less than 1, is there a way to manipulate `(1 * NSEC_PER_SEC)`? – Eric Oct 20 '15 at 21:44
  • @Eric If you want a delay, you just need `dispatch_after`. – rmaddy Oct 20 '15 at 21:44
  • @Eric Change the `1` to `0.5` or whatever amount you need. It's a float value in seconds. – rmaddy Oct 20 '15 at 21:44
  • @maddy yeah you're right, I removed that part from the sample code. Thanks for pointing it out – manman Oct 20 '15 at 21:45
  • It crashed with `0.5.` In any case it is working wonderfully following @rmaddy's comments to remove the `dispatch_async`. Thanks, @rmaddy. @manman Can you upvote the question? – Eric Oct 20 '15 at 21:46
1

If you are waiting for something to download or something, you may also consider using a block that is called (and presents the view controller) once the task is complete. If you do this you should also use some sort of loading animation.

Raesu
  • 310
  • 2
  • 15
  • Thanks, @Raesu. I am not waiting for anything to download. The key is to display an alert updating a user's coin purse with coins earned from an offer wall. The callback is lightening fast so there is no need to wait, unless, of course, there is something missing. – Eric Oct 20 '15 at 21:26
  • Got it. In @manman's answer I actually prefer the `performSelector:...afterDelay:` method, cleaner code. – Raesu Oct 20 '15 at 21:41
  • Must selectors be either methods, functions, or actions, right? Alert is an instance of the class UIAlertViewController. Can I call an ivar as a selector? – Eric Oct 20 '15 at 21:46
  • I believe they have to be methods. I just make a method to execute that code, then use `performSelector:...afterDelay:` to call it. No GCD spaghetti code! – Raesu Oct 20 '15 at 21:53
  • If `performSelector:afterDelay:` requires a method, then I understand now why @manman's solution with GCD works in lieu of the remaining two! Thanks for the explanation! – Eric Oct 20 '15 at 21:55