I have an iPhone app which sends an email. If the "To:" address is not set, I display an Alert (UIAlertView). At the present time, I do not check for the user tapping OK, I just go on my merry way! :D
I am getting the following error when tapping OK on the Alert:
wait_fences: failed to receive reply: 10004003
I believe it's because I don't handle the tapping of OK and it's still showing when the app is doing something else. So, after doing some research on SO and Google, it appears I have to have this:
- (void) Alert: (NSString *) title andData: (NSString *) errorMsg {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: title
message: errorMsg
delegate:nil
cancelButtonTitle: #"OK"
otherButtonTitles: nil];
[alert show];
return;
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"button was pressed");
}
My problem is that I can't figure out how to set up the delegate for this. I already have a delegate:
#interface ReportViewController : UIViewController <UIWebViewDelegate> {
How do I set the delegate so the tap of the OK button is handled, thus removing the error?
Inside the angle brackets, you can provide a comma-separated list of protocols.
#interface ReportViewController : UIViewController <UIWebViewDelegate, UIAlertViewDelegate> {
Now you can implement both sets of methods. And don't forget to set the alert view's delegate to self.
Your delegate looks like nil as per your code 'delegate:nil' in the question. You need to change it to 'delegate:self'.
Related
Am new to AlertViews with actions. Have set mine up as in the examples I found here including setting the delegate method in my .h, but when I debug find that it is not reaching my clickedButtonAtIndex method. Probably missing something simple :-/ Any help solving this would be appreciated, thanks.
Here's my code:
.h file
#interface LineDetailViewController : UIViewController <UIAlertViewDelegate>
. m file:
- (IBAction)removeLineButton:(UIButton *)sender {
NSString * requestSubmitText = [NSString stringWithFormat:#"Hey Bro are you sure you want to remove this line you created, it will also remove all the reviews attached and can not be undone?"];
UIAlertView *removeLineRequest = [[UIAlertView alloc] initWithTitle:#"WARNING!!"
message:requestSubmitText
delegate:nil
cancelButtonTitle:#"Remove It"
otherButtonTitles:#"Cancel",nil];
[removeLineRequest show];
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex{
//if (buttonIndex == [alertView cancelButtonIndex]){
if (buttonIndex == 0){
NSLog(#"Cancel button pressed");
}else{
NSLog(#"other button pressed");
}
}
You have to set delegate to self
UIAlertView *removeLineRequest = [[UIAlertView alloc] initWithTitle:#"WARNING!!"
message:requestSubmitText
delegate:self // <- here
cancelButtonTitle:#"Remove It"
otherButtonTitles:#"Cancel",nil];
Call removeLineRequest.delegate = self.
While creating your alert view set your delegate to self . And you have already implemented the UIAlertViewDelegate.
To solve your problem, just set the delegate to self instead of nil.
Some additional info,
UIAlertView and UIAlertViewDelegate have been deprecated. As per the documentation,
UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead.
Relevant tutorial here
So I have two different UIAlertViews in the same view controller and both alerts can be triggered at the same time. When both alerts are triggered, both alerts pop up at the same time, with the alerts being layered on top of each other. Is there a way to stagger the alerts so that when the first alert comes up, the second alert will not pop up until the user dismisses the first alert? For my code, this is the format I'm using
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"ERROR!"
message:#"Error message here!"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
try the following:
create two properties
#property (weak, nonatomic) UIAlertView *visibleAlertView;
#property (strong, nonatomic) UIAlertView *pendingAlertView;
every time when you want to present an alertview from your code make a check
UIAlertView *newAlertView = [[UIAlertView alloc] init...
if (self.visibleAlertView) {
self.pendingAlertView = newAlertView;
} else {
self.visibleAlertView = newAlertView;
[newAlertView show];
}
and finally:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (self.pendingAlertView) {
UIAlertView *newAlertView = self.pendingAlertView;
self.pendingAlertView = nil;
self.visibleAlertView = newAlertView;
[newAlertView show];
}
}
hope that helps :)
EDIT
you could even stack the pending alertviews:
#property (strong, nonatomic) NSMutableArray *pendingAlertViews;
...
self.pendingAlertViews = [NSMutableArray array];
before presenting an alertview:
UIAlertView *newAlertView = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
if (self.visibleAlertView) {
[self.pendingAlertViews addObject:newAlertView];
} else {
self.visibleAlertView = newAlertView;
[newAlertView show];
}
and in dismiss:
if (self.pendingAlertViews.count > 0) {
UIAlertView *av = self.pendingAlertViews.firstObject;
[self.pendingAlertViews removeObjectAtIndex:0];
self.visibleAlertView = av;
[av show];
}
hope it helps :)
Why don't you make a class level variable that indicates an alertView is open. Then before you open one you check that variable and if it's set you don't pop up the second one. Instead you could have it set another variable that indicates the second box should pop up. Then in the - alertView:clickedButtonAtIndex: method you can pop up the second one if the second variable is set.
I think I am pretty late for this but still posting as It might be useful for someone looking for this.
I have created a AQAlertAction subclass for UIAlertAction. You can use it for staggering Alerts, the usage is same as you are using UIAlertAction. All you need to do is import AQMutiAlertFramework in your project or you can include class also (Please refer Sample project for that). Internally It uses binary semaphore for staggering the Alerts until user handle action associated with current alert displayed. Let me know if it works for you.
I have a class that I instance to show an alert view like this:
- (void)showAlert
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Do you want to try again?"
message:nil
delegate:self
cancelButtonTitle:#"Yes"
otherButtonTitles:#"No", nil];
[alertView show];
}
}
I need self to be the delegate because I need alertView:didDismissWithButtonIndex: to be called to perform some actions when the user taps the alert view's button. This usually works well, but from time to time, I get this crash:
SIGSEGV
UIKit-[UIAlertView(Private) modalItem:shouldDismissForButtonAtIndex:]
I guess this is because the delegate, for any reason, was released, right? Or is this because what was released was the alert view? How could I solve this? I need the alert view to have a delegate, and I've reading several related posts and I couldn't find an answer that fits my scenario.
I'm testing in iOS 7.0, I don`t know if that could have to do with the issue.
Thanks in advance
It seems that you tap alert when its delegate is released:
delegate:self
It happens because UIAlertView delegate property is of assign type (not weak!).
So your delegate potentially can point to released object.
Solution:
in dealloc method you need to clear delegate for your alertView
- (void)dealloc
{
_alertView.delegate = nil;
}
But before you need to make iVar _alertView and use it for your alertViews
- (void)showAlert
{
_alertView = ...;
[_alertView show];
}
Update your code as follows:
- (void)showAlert {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Do you want to try again?"
message:nil
delegate:self
cancelButtonTitle:#"Yes"
otherButtonTitles:#"No", nil];
[alertView show];
}
Its due to you are missing the nil for otherButtonTitles part.
Missing sentinel in method dispatch warning will be shown if you didn't add nil.
That's because the alertView's delegate object released while clicking the button. I think it's a bug of SDK:
#property(nonatomic,assign) id /*<UIAlertViewDelegate>*/ delegate; // weak reference
should be:
#property(nonatomic, weak) id /*<UIAlertViewDelegate>*/ delegate; // weak reference
To fix the issue:
add a weak delegate for UIAlertView using association.
swizzle the init, setDelegate: delegate methods, set alertView delegate to self, set step 1 weak delegate with the param delegate.
implement all delegate methods, deliver the methods using the weak delegate.
In my application i want alertview in many views.So what i did is just wrote a single alertview in a utility class and use it everywhere.This is working fine.
I even tried by setting <UIAlertViewDelegate> but in vain.
Utility Class
#interface SSUtility: NSObject<UIAlertViewDelegate> {
}
+(void)showAllert;
#end
#implementation SSUtility
+(void)showAllert{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"gotoappAppstore",#"") message:#"" delegate:self cancelButtonTitle:NSLocalizedString(#"Ok",#"") otherButtonTitles:nil];
[alert show];
[alert release];
}
#end
Now from my view
-(void)pressButton{
[SSutility showAllert]
}
Now i want to give a button action for alert view click and call a method on that button action.
So im stuck with,in which class i want to implement this method.I tried it in utility class and viewc controller but the method is not getting triggered when "ok" button is pressed.
-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
Can anyone please help me on this?
Thanks in advance.
You wire the alert view button response method by setting your alert view object delegate usually to the owner object and implementing the – alertView:clickedButtonAtIndex: method.
You need 4 parts in your code:
instantiate your UIAlertView object
send show message to your UIAlertView object
set delegate
implement the delegate method
Example:
UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:#"myTitle" message:#"myMessage" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitle:#"Another button"];
[myAlertView setDelegate:self];
[myAlertView show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) //index 0 is cancel, I believe
{
// code for handling cancel tap in your alert view
}
else if (buttonIndex == 1)
{
// code for handling button with index 1
}
}
I would recommend you get more familiar with how delegates work. This'll come back again a lot.
You set delegate:nil in your UIAlertView's init.
You should set to delegate:self, like this:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"gotoappAppstore",#"") message:#"" delegate:self cancelButtonTitle:NSLocalizedString(#"Ok",#"") otherButtonTitles:nil];
in order to use the delegate in the same class (a.k.a. self).
As a sidenote, if you use Automatic Reference Counting (ARC), you do not need [alert release] (your Xcode compiler should warn you about this)
I have been googling this problem for almost a whole day now, without getting any closer to a solution, so i would like to ask you guys.. :)
I'm working on an iOS app, which should connect to a mbed over WiFi and give the user a dialog if it connects and if it doesn't and if not, then give the user the possibility to retry.
My problem is now that i have implemented the connecting method in appdelegate.m and it is from here I would like to show the alerts..
The alerts it self works fine, but I have problems detecting when a button is pressed, the clickedButtonAtIndex is not being called.
I have added the UIAlertViewDelegate in the appdelegate.h, like so:
#interface AppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate, UIAlertViewDelegate>
and have set the delegate to self, in the alertview, like so:
alert_NOT = [[UIAlertView alloc] initWithTitle:#"Not connected!" message:message_to_user delegate:self cancelButtonTitle:#"Try again" otherButtonTitles: nil];
[alert_NOT show];
[alert_NOT release]
and the clickedButtonAtIndex looks like
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"test");
}
So I would love to see the word "test" in the log when a button is pressed in the alertview, but nothing happens.
Update:
Tried implementing it in my "FirstViewController.m" and there it works :S but I would very much like to have it in the appdelegate.m if possible..
I'm currently looking into a similar implementation and would like to share an idea I had with you: perhaps using an NSNotification that fires when your delegate's conditions are met, which can be listened for in your VC(s) and handled appropriately, with an alert view, at the top of the stack.
#interface urAppDelegate : NSObject <UIApplicationDelegate,UIAlertViewDelegate>
If you synthesized the alert_not then use it like this with self:
self.alert_NOT = [[UIAlertView alloc] initWithTitle:#"Not connected!" message:message_to_user delegate:self cancelButtonTitle:#"Try again" otherButtonTitles: nil];
[alert_NOT show];
[alert_NOT release];
You should use the alertViewCancel method for this.
- (void)alertViewCancel:(UIAlertView *)alertView
{
NSLog(#"text");
}
Define as below:
#define appDelegate ((AppDelegate*)[UIApplication sharedApplication].delegate)
and alert as:
UIAlertView *alert_NOT = [[UIAlertView alloc] initWithTitle:#"Not connected!" message:message_to_user delegate:appDelegate cancelButtonTitle:#"Try again" otherButtonTitles: nil];
[alert_NOT show];
Here set delegate as defined keyword, i.e., appDelegate.
Hope this helps.