UIAlertViewDelegate clickedButtonAtIndex: usefulness? - iphone

The UIAlertViewDelegate protocol defines two methods, alertView:clickedButtonAtIndex: and alertView:didDismissWithButtonIndex:, which seem to me to be identical in usefulness.
Why is there a clickedButtonAtIndex and a didDismissButtonWithIndex when they both do the same thing? I realize there is also a willDismissButtonWithIndex that happens before the alert view is dismissed, but is there any reason to use clickedButtonAtIndex instead of didDismissButtonWithIndex?

I found a more useful difference between the two:
When showing a UIAlertView, and the device goes to sleep, alertView:didDismissWithButtonAtIndex: gets called, even though the alert view is not actually dismissed. It is shown again once the device wakes up. alertView:clickedButtonAtIndex: is only called when the user clicks one of the buttons.

The alertView:clickedButtonAtIndex: is called when the user clicks a button on an alert view whereas the alertView:didDismissWithButtonIndex: is called after an alert view is dismissed from the screen. (See the UIAlertViewDelegate Protocol Reference.)
The difference is minimal but it allows you to do something before or after animation.

If the alert view disappears for any reason (including being covered by another UIAlertView, going to sleep, etc.), didDismissWithButtonAtIndex: is called. This can mean that the method can be called even without the user clicking on anything. This can lead to unexpected behaviour if you depend on this delegate callback to be called in response to the user actually clicking on a button. In this case clickedButtonAtIndex: is more useful.

I couldn't reproduce Ed's behaviour by locking my device with the alert view present on iOS 7.
However, the most important difference between alertView:clickedButtonAtIndex:, alertView:didDismissWithButtonIndex: and alertView:willDismissWithButtonIndex: is that the first method (clickedButtonAtIndex:) is only called when the user explicitly taps on a button on your alert view (hence 'clicked').
Is it possible that an alert view is dismissed without clicking on a button? Yes, you could programmatically hide an alert view using the UIAlertView method dismissWithClickedButtonIndex:animated:.
So, if you need some behavior to be always triggered upon the dismissal of the alert view—whether it was triggered by the user tapping on a button or triggered programmatically—then using the didDismissWithButtonIndex: and willDismissWithButtonIndex: makes more sense.

Related

Why would alert view delegate method not get called?

In my interface file I said I conform to the UIAlertViewProtocol and I implemented the alertView:clickedButtonAtIndex: method in my implementation file, and normally whenever the alertview button is pressed (the button that makes the alert go away)that method gets called. Well, it gets called most of the time, but for one of my alert views it doesn't get called after I press the cancel button on it, what would be a reason for this?
Oh Its because in one of my alert views for the delegate parameter i passed in nil instead of self, thats embarassing.

Programmatically dismissing a UIAlertView on iOS 5 doesn't call didDismiss delegate method

I'm running into a problem where 9 times out of ten, when I call UIAlertView's dismissWithClickedButtonIndex:animated:, the delegate method alertView:willDismissWithButtonIndex: is not called. Is anyone else running into this problem? I'm about to file a bug with Apple but I'm curious to see if anyone else has run into this issue and figured out any workarounds.
To ensure a consistent behavior across iOS4 and 5, you could just remove the UIAlertView's delegate just prior to calling its dismissWithClickedButtonIndex:animated: method, then manually invoke the delegate method. e.g.
- (void)somethingDidHappen {
id<UIAlertViewDelegate> delegate = myAlertView.delegate;
myAlertView.delegate = nil;
// now, we know the delegate won't be called...
[myAlertView dismissWithClickedButtonIndex:0 animated:NO];
// ...so we call it ourselves below
[delegate alertView:myAlertView clickedButtonAtIndex:0];
}
(That code isn't tested, but you get the point.)
Delegates of UI objects are only called when the user performs an action. Apple assumes that when you do something from code, you already know what you're doing and you don't need to be informed. That applies to all delegates (scrolling delegate methods of UIScrollView vs. code-scrolling, Table View manipulation, ...)
Anyway, what button index should the delegate be called with?.. there is no one when you dismiss programmatically
According to Why doesn't dismissWithClickedButtonIndex ever call clickedButtonAtIndex? the problem is that a different method is being called. However, that doesn't explain why you get erratic calls. On the devices I tested the dismiss method gets called correctly, so I only redirect it to the click version.
Maybe you should file a bug with Apple if you continue seeing the erratic behaviour.
There are alertView:clickedButtonAtIndex:, alertView:didDismissWithButtonIndex: and alertView:willDismissWithButtonIndex:. The method that you're referring to (clickedButtonAtIndex:) is only called when the user explicitly taps on a button on your alert view (hence 'clicked').
Programmatic calls via dismissWithClickedButtonIndex:animated: to dismiss the alert does not seem to call alertView:clickedButtonAtIndex:.
So, if you need some behavior to be always triggered upon the dismissal of the alert view—whether it was triggered by the user tapping on a button or triggered programmatically—then using the didDismissWithButtonIndex: and willDismissWithButtonIndex: makes more sense.

iPhone app entering background state and presenting a UIAlertView

If an app delegate receives the -willResignActive message and a UIAlertView is within 0.5 seconds of being shown, the app will present two alert views (one a duplicate) when it becomes active once more.
This is a problem, because if responding to the first alert view means there are no responders to the duplicate (likely!) the app will just crash.
Thoughts?
The best solution I have is to retain a static reference to a UIAlertView, dismiss (with clicked button index -1), release, and then allocate/init a new instance at the same address. This makes sure there's only ever one alert view scheduled or showing. If an alert view is already showing, ignore (or manage) the new request (failsafe popping to root view or some such).
It's not very satisfactory because UIAlertViews have nothing to do with the workings and shouldn't be static. In my mind at least.

Dismiss or destroy all view controllers, action sheets, etc?

I'm implementing a custom URL scheme in my navigation based app to let users import data from an email, and so I have this method in my app delegate:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
It would be nice, if after importing the data in that method, I could use popToRootViewController to go back to the rootViewController to show the user the new data.
However, that doesn't work if the user had imported the data while a modal view controller or action sheet was up (popToRootViewController doesn't dismiss those, and causes the app to freeze).
Is there any way I can safely dismiss/destroy all view controllers/action sheets/alert views except for the rootViewController?
Or perhaps some way to tell from within my app delegate if the user has an action sheet or modal view controller up?
Or, do I just leave them where they left off, and not provide any immediate indication that data was successfully added?
You'll have to keep track of them yourself. An easy way to do that is to post a notification, with a reference to the modal view/sheet/alert in the userinfo dictionary, every time you display something modal. Whenever a modal view returns, post a different notification.
Observe the notifications in your app delegate (or wherever it makes sense to do so, but the app delegate is simplest). When you receive the first one, store a (weak) reference to the modal view, and zero the reference when you receive the second one. In between, you'll be able to respond to -application:handleOpenURL: by dismissing the modal view if your reference is non-nil.
Note also that in the case of alerts, it's probably best to dismiss them when you enter the background. Weeks might pass before you are foregrounded again, and it's bad style to greet the user with "Are you sure? OK/Cancel" when they may no longer have any idea what you're asking about.

Is there a way to dismiss an alertview automatically after some time?

I'm looking for a way, to automatically dismiss an alert view after some time or after a task is done.
Is there a possibility? (or another way to show a message for some time?)
You can call the -dismissWithClickedButtonIndex:animated: method to dismiss the alert view.
To dismiss it automatically, create an NSInvocation and then use -performSelector:withObject:afterDelay: to -invoke it.
UIAlertView has a method called:
- ( void )dismissWithClickedButtonIndex: ( NSInteger )buttonIndex animated:( BOOL )animated
You can call it on your UIAlertView object to simulate a button press.
To dismiss it automatically after some time, you will need something like an NSTimer, to check if the alert view is still displayed, and in such a case, dismiss it.