I want to show multiple messages on iOS one by one, but the problem is that showing UIAlertView is non-blocking. I tried to handle alert closing with clickedButtonAtIndex and show same alert inside. Here is some code:
#interface ViewController : UIViewController <UIAlertViewDelegate>
...
#property UIAlertView *alert;
...
#end
...
[alert show]; //somewhere in code, starts chain of messages
...
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Some changes in alert object
[alert show];
}
I would have one UIAlertView and change its message on button click... Maybe increment its tag as well
try overriding
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
instead of clickedButtonAtIndex
I prefer to set tags on the alert views:
#define ALERT_1 1
#define ALERT_2 2
...
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:...];
alert.tag = ALERT_1;
[alert show]; //somewhere in code, starts chain of messages
...
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (alertView.tag) {
case ALERT_1: {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:...];
alert.tag = ALERT_2;
[alert show];
} break;
case ALERT_2: {
....
} break;
}
}
This way you don't have to use variables for the alert views.
You need one property for each alert view you want to show. In the delegate function check which one finished and start the next one:
#interface ViewController : UIViewController <UIAlertViewDelegate>
...
#property UIAlertView *alert1;
#property UIAlertView *alert2;
#property UIAlertView *alert3;
#end
...
alert1 = [[UIAlertView alloc] initWithTitle:...];
[alert1 show]; //somewhere in code, starts chain of messages
...
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView == alert1) {
alert2 = [[UIAlertView alloc] initWithTitle:...];
[alert2 show];
} else if (alertView == alert2) {
alert3 = [[UIAlertView alloc] initWithTitle:...];
[alert3 show];
}
}
Related
Yes, I've already Googled this question and I've used the exact code, but that's still not working.
Here is my current Objective-C code:
- (IBAction)btnTemp:(id)sender
{
if (_deepSwitch.on == TRUE)
{
[self TempCleaner];
_progress.progress += 1;
}
UIAlertView *cleaned = [[UIAlertView alloc] initWithTitle:#"Done!" message:#"Your device is now clean. Restarting SpringBoard." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[cleaned show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == [alertView cancelButtonIndex]) {
NSLog(#"clicked");
}
}
Why isn't this working? I've tried buttonIndex 0, and cancel button!
Set the alert view's delegate to self
UIAlertView *cleaned = [[UIAlertView alloc] initWithTitle:#"Done!" message:#"Your device is now clean. Restarting SpringBoard." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
Also, make sure that the class from which you are presenting the alert view declares the UIAlertViewDelegate protocol
//YourClass.h
#interface YourClass : SuperClass <UIAlertViewDelegate>
-(void)otherGames
{
UIAlertView *alertMsg = [[UIAlertView alloc]
initWithTitle:#"This gGame was Developed By:"
message:#"Burhan uddin Raizada"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles: #"#twitter" , nil];
[alertMsg show];
}
-(void)alertMsg:(UIAlertView *)alertMsg clickedButtonAtIndex:(NSInteger)buttonIn… {
if (buttonIndex == 1) {
NSString *containingURL = [[NSString alloc] initWithFormat:#"http://www.twitter.com/…
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: containingURL]];
}
}
the first alertmsg is working absolutely fine. but when i added a like to the new "#twitter" button, then it just doesn't work. otherwise everything is working fine. i am wondering why it doesn't, but it should..need help.
Assuming that
- (void)alertMsg:(UIAlertView *)alertMsg clickedButtonAtIndex:(NSInteger)buttonIn…
is
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
You must set your delegate to self and add the delegat protocol to your header :
#interface yourView : UIViewController <UIAlertViewDelegate>
Edit : According to #holex, use alertView:willDismissWithButtonIndex: instead of -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
UPDATE
this answer has been outdated since UIAlertView is deprecated in iOS8.
you can read more about UIAlertController on Apple's Dev Docs.
FIRST:
you haven't delegated your class, delegate:nil shows there is no delegated class for the UIAlertView. your should correct your method following this:
-(void)otherGames
{
UIAlertView *alertMsg = [[UIAlertView alloc]
initWithTitle:#"This gGame was Developed By:"
message:#"Burhan uddin Raizada"
// delegate:nil
delegate:self // don't forget to implement the UIAlertViewDelegate protocol in your class header
cancelButtonTitle:#"Dismiss"
otherButtonTitles: #"#twitter" , nil];
[alertMsg show];
}
SECOND:
the correct name of the callback method is: -alertView:didDismissWithButtonIndex:
//-(void)alertMsg:(UIAlertView *)alertMsg clickedButtonAtIndex:(NSInteger)buttonIn… { // WRONG, where have you got this silly idea...?
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
NSString *containingURL = [[NSString alloc] initWithFormat:#"http://www.twitter.com/…
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: containingURL]];
}
}
now, you know why your code fragment is wrong.
I want two alert views to show up only when the user opens my application for the first time -- the second to appear after the first is dismissed. I have it set up to only show the UIAlertViews when it has not been shown before and I do not need help with this. I need help figuring out how to display two alert views in a row when this is the case.
-(void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex does not work for me.
Here is the code I have -- remember this is in didFinishLaunchingWithOptions:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL didFirstLaunch = [defaults boolForKey:#"DidFirstLaunch"];
if (!didFirstLaunch) {
[defaults setBool:YES forKey:#"DidFirstLaunch"];
UIAlertView *successAlert = //not important
[successAlert show];
[successAlert release];
//Somehow show second alert after the first is dismissed
}
I'm gonna post a very simple solution using GCD & blocks (GCD part is just in case the alert view is created on another thread then the main thread, callback should be safe to perform on the main thread). Remember, I just coded this in like 5 mins, so you definitely should work on improving the code. One thing that's a bit ugly is the delegate parameter that is overridden in my subclass. The interface of the subclass could be changed a bit to make it more obvious of what happens ...
Anyway, here goes ...
First create a subclass of UIAlertView, make it look somewhat like the following ...
#interface FSAlertView () <UIAlertViewDelegate>
#property (nonatomic, copy) void (^dismissHandler)(NSInteger buttonIndex);
#end
#implementation FSAlertView
#synthesize dismissHandler = _dismissHandler;
- (void)showWithDismissHandler:(void (^)(NSInteger buttonIndex))dismissHandler
{
self.dismissHandler = dismissHandler;
self.delegate = self;
[self show];
}
// Alert view delegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
dispatch_async(dispatch_get_main_queue(), ^ {
if (_dismissHandler)
{
_dismissHandler(buttonIndex);
}
});
}
Now in the app we can create alert views like the following ...
FSAlertView *alert1 = [[FSAlertView alloc] initWithTitle:#"Alert 1"
message:#"Some message"
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Show 2nd Alert", nil];
[alert1 showWithDismissHandler:^ (NSInteger buttonIndex) {
NSLog(#"button pressed: %d", buttonIndex);
if (buttonIndex == 1)
{
UIAlertView *alert2 = [[UIAlertView alloc] initWithTitle:#"Alert 2"
message:#"Hi!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert2 show];
}
}];
If i understand your question correctly , then this may help:
UIAlertView *firstAlert = [[UIAlertView alloc] initWithTitle:#"Alert 1" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[firstAlert show];
[self performSelector:#selector(test:) withObject:firstAlert afterDelay:2];
[firstAlert release];
UIAlertView *secondAlert = [[UIAlertView alloc] initWithTitle:#"Alert 2" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[secondAlert show];
[self performSelector:#selector(test:) withObject:secondAlert afterDelay:2];
[secondAlert release];
-(void)test:(UIAlertView*)alert{
[alert dismissWithClickedButtonIndex:-1 animated:YES];
}
This will show two alert views one after the other.
NOTE: I am not sure if you are dismissing the alerts with cancel button so i am dismissing them automatically after few seconds.
Try this:
UIAlertView *firstAlert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[firstAlert setTag:444];
[firstAlert show];
firstAlert = nil;
AlertView Delegate Method:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
switch (alertView.tag) {
case 444:
{
//Cancel ButtonIndex = 0
if (buttonIndex == 1) {
UIAlertView *secondAlert = [[UIAlertView alloc] initWithTitle:#"Title 2" message:#"Message2" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Dismiss", nil];
[secondAlert setTag:555];
[secondAlert show];
secondAlert = nil;
}
}
break;
case 555:
{
if (buttonIndex == 1) {
NSLog(#"Code Here");
}
}
break;
}
}
Say I have a alert view like follows in obj c
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"title" message:#"szMsg" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:#"download"];
[alert show];
[alert release];
Now we have 2 buttons on the alert view (Ok & Download), how to write an event handler for the Download one?
First you will need to add the UIAlertViewDelegate to your header file like below:
Header file (.h)
#interface YourViewController : UIViewController<UIAlertViewDelegate>
Implementation File (.m)
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"title" message:#"szMsg" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:#"download"];
[alert show];
[alert release];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
//Code for OK button
}
if (buttonIndex == 1)
{
//Code for download button
}
}
Now that most iOS devices have firmare versions with blocks support it’s an anachronism to use the clumsy callback API to handle button presses. Blocks are the way to go, see for example the Lambda Alert classes on GitHub:
CCAlertView *alert = [[CCAlertView alloc]
initWithTitle:#"Test Alert"
message:#"See if the thing works."];
[alert addButtonWithTitle:#"Foo" block:^{ NSLog(#"Foo"); }];
[alert addButtonWithTitle:#"Bar" block:^{ NSLog(#"Bar"); }];
[alert addButtonWithTitle:#"Cancel" block:NULL];
[alert show];
Declare your UIAlertViews as known.
UIAlertView *alertLogout=[[UIAlertView alloc]initWithTitle:#"Title" message:#"Stop Application?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes",nil];
[alertLogout show];
[alertLogout release];
set delegate to self and implement this method.
-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(actionSheet== alertLogout) {//alertLogout
if (buttonIndex == 0){
}else if(buttonIndex==1){
}
}else if (actionSheet==alertComment) {//alertComment
if (buttonIndex==0) {
}
}
}
Stack's and Guillermo Ortega's answer is probably what you would use with a couple of UIAlertView but not for ten. I use to use BlocksKit which is kind of the same as Lambda stuff which is what soul suggested. That is a good option too, although if you have too many nested blocks you will start seeing the demerits of it (Aside from the fact you will be relying in another library).
The usual way of handling several stuff would be to have a handler object. (
#interface MyAlertViewDelegate : NSObject <UIAlertViewDelegate> #end) make that object the delegate of the alert view and make sure the object is alive at least until the alert view is dismissed.
This will certainly work, but could be too much work...
What follows is what I came up with; IMO it is simpler and there is no need of any thirdParty library, or an ivar per UIAlertView. Just one extra object (#property (nonatomic, strong) NSArray *modalActions) to store the actions the current UIAlertView will cause to perform
Showing an UIAlertView and reacting accordingly
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle
message:#"Blah blah"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:b1, b2, b3, nil];
// Add one selector/action per button at the proper index
self.modalActions = #[
[NSNull null], // Because indexes of UIAlertView buttons start at 1
NSStringFromSelector(#selector(actionForAlertViewButton1)),
NSStringFromSelector(#selector(actionForAlertViewButton2)),
NSStringFromSelector(#selector(actionForAlertViewButton3))];
[alertView show];
The delegate method:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (alertView.cancelButtonIndex != buttonIndex) {
[self performModalActionAtIndex:buttonIndex];
}
}
The part that actually performs the action:
- (void)performModalActionAtIndex:(NSInteger)index
{
if (-1 < index && index < self.modalActions.count &&
[self.modalActions[index] isKindOfClass:[NSString class]]) {
SEL action = NSSelectorFromString(self.modalActions[index]);
NSLog(#"action: %#", self.modalActions[index]);
if ([self respondsToSelector:action]) {
// There is a situation with performSelector: in ARC.
// http://stackoverflow.com/questions/7017281/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:action];
#pragma clang diagnostic pop
}
self.modalActions = nil;
}
Reusable for UIActionSheets too
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:title
delegate:self
cancelButtonTitle:cancelButton
destructiveButtonTitle:nil
otherButtonTitles:button1, button2, button3, nil];
// Similarly, add one action per button at the proper index
self.modalActions = #[
NSStringFromSelector(#selector(actionForActionSheetButton1)),
NSStringFromSelector(#selector(actionForActionSheetButton2)),
NSStringFromSelector(#selector(actionForActionSheetButton3))];
The delegate method:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (actionSheet.cancelButtonIndex != buttonIndex) {
[self performModalActionAtIndex:buttonIndex];
}
}
Why this works:
This works because of two reasons:
First, I never present two UIAlertView that have a delegate at the same time. (IMO you should't, it doesn't look good). Second, because in my case (as 90% of the cases) the target of the actions is always the same object (in this case: self). Even if you don't meet above conditions you can even use this approach with some modifications:
If you show two or more UIAlerViews or UIActionSheets at the same time (possible in the iPad) Use a dictionary with to store one array of actions associated with a certain UIAlertView/UIActionSheet.
If the target of the actions is not self, they you need to store pairs (target and the action) in the array. (Something to simulate UIButtons addTarget:action:...).
In either case, for storing the target and/or UIActionSheet/UIAlertView [NSValue valueWithNonretainedObject:] should become handy :)
First of all you declare UIAlertViewDelegate in .h file after put below code in .m file
- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
//put button action which you want.
}
}
Implement the UIAlertViewDelegate and make use of the delegate method
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0) {
// Do something
}
else {
// Do something
}
}
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Data Saved" message:#"Choose more photos" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:Nil];
[alertView show];
[alertView release];
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex==0)
{
[self dismissModalViewControllerAnimated:YES];
}
}
in swift:
we can use this little block of code
let alert = UIAlertController(title: "Alert", message: "This is an alert message", preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {(action:UIAlertAction) in print("This is in alert block")
})
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
I used Facebook SDK on my app. After i pressed "Add feed to your wall", the alert pops up with "YES" or "NO". If i choose "YES" the FBStreamDialoy just flash away.
First , click the button " Add feed to your wall" to call changeFeed: function:
-(IBAction) changeFeed
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sporting Summer Festival Monte-Carlo" message:#"Are you attending this concert?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes",nil];
[alert show];
alert.tag = 1;
self.alertView =alert;
[alert release];
}
Then, press "YES" button. Call this function:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"NO");
}
else
{
NSLog(#"YES");
[self showAddFeed];
}
}
And this is the showAddFeed function , which is defined in front of clickButtonAtIndex.
-(void)showAddFeed
{
FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
dialog.delegate= self;
dialog.userMessagePrompt = #"*****";
[dialog show];
}
Just cant work well. I don't know why? Thank you for your help.
------------Answer is--------------------------
[self performSelector:#selector(fbButtonClick) withObject:nil afterDelay:0.10];
Call it after a delay of 0.1 sec [self performSelector:#selector(fbButtonClick) withObject:nil afterDelay:0.10];
The problem is that you listen to:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
Which should be:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
Because at the clickedButtonAtIndex function the view isn't closed and this can cause problems.
Edit:
To make it work in iOS 4 add your facebook login call to a method and call the following function in the didDismissWithButtonIndex:
[self performSelectorOnMainThread:#selector(facebookOpenAction) withObject:nil waitUntilDone:NO];