Please excuse me if something is not post right... first time posting.
I have seen a few questions simular to this but none with the same problem. I am running IOS 6.1 and Xcode 4.6. The problem is that didDismiss is never called, only willDismiss. My code is below along with the log output. Any ideas?
#import "MenkLabUIAlertTestViewController.h"
#interface MenkLabUIAlertTestViewController ()
#end
#implementation MenkLabUIAlertTestViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)test:(id)sender {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Encrypting File(s)" message:#"Please wait..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
// UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[av show];
[av dismissWithClickedButtonIndex:-1 animated:YES];
}
- (void) alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
NSLog(#"willDISMIS");
}
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSLog(#"didDISMIS");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Log output:
2013-07-08 17:27:04.055 testUIAlertView[10534:11303] willDISMIS
This is just a test app, however, it is the exact same problem that exists in my current application.
Thanks in advanced. Been racking my head on this all day!
I think this an artifact of the fact that you are showing, then immediately dismissing the alert view in the same method -- you would never actually do this in a real app. If you create a property for the alert view, and then do the test like below, it works fine:
- (IBAction)test:(id)sender {
self.av = [[UIAlertView alloc] initWithTitle:#"Encrypting File(s)" message:#"Please wait..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[self.av show];
[self performSelector:#selector(dismissAlertView) withObject:nil afterDelay:1];
}
-(void)dismissAlertView {
[self.av dismissWithClickedButtonIndex:-1 animated:YES];
}
- (void) alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
NSLog(#"willDISMIS");
}
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSLog(#"didDISMIS");
}
I had faced a similar issue, as a workaround we added a selector Method which runs after some delay which will instead trigger the dismissal of alert view. I am not sure why it does not work if we ask the alert to to dismiss immediately after it is shown. Hope it helps.
I ran into this problem too. For me it was related to trying to programatically dismiss it with a button index on -1. We ended up going down a different path in the end for other reasons. However, There is a cancel button index on the actionsheet that you can try calling it with.
I ran into this problem once. For me the problem was caused by a collision between animations. The didDismiss selector is called when the animation ends. If another animation is started between willDismiss and didDismiss then in some rare circumstances the didDismiss doesn't have to be called.
Also note that it never works well if you try to dismiss the alert before it is fully displayed.
I have added. That solves my problem.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
}
}
Related
Why doesn't this code work? All I have is this:
-(void)_webview:(UIWebView *)_webview didFailLoadWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!" message:#"You have no internet connection!" delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil, nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
exit(0);
}
It should work, right?
Because you mistyped the name of the UIWebViewDelegate method. You have
_webview:didFailLoadWithError:
whereas the real name of this method is
webView:didFailLoadWithError:
The delegate method is mistyped, as stated in the above response. Also, did you set the delegate of the UIWebView to the instance of the class that has those methods implemented?
for example, if it's a view controller, it could be in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
_webView.delegate = self;
}
I have iPhone and I want that when AlertView is shown and user presses OK button after that view should be changed but it is not happening.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Thank you" message:#"" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
return;
[self moveToView];
-(void)moveToView
{
MainViewController*targetController=[[MainViewController alloc]init];
[self.navigationController pushViewController:targetController animated:YES];
}
Please use UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Code to move to next view
[self moveToView];
}
Note: Implement the UIAlertViewDelegate in your interface Declaration. Also while declaring UIAlertView set the delegate to self.
Hope this helps you.
Its simple. Implement UIAlertViewDelegate and put code there.
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
MainViewController*targetController=[[MainViewController alloc]init];
[self.navigationController pushViewController:targetController animated:YES];
[targetController release];
}
in .h , implemented UIAlertViewDelegate
#interface ClassName : ParentClassName <UIAlertViewDelegate>
in .m , Add this method,
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[self moveToView];
}
Implement alert view's delegate:
In your yourClass.h file:
#interface yourClass : UIViewController<UIAlertViewDelegate>{
}
#end
In your yourClass.m file:
#implementation yourClass
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
[self moveToView];
}
#end
Well , you are setting self as the delegate of the UIAlertView. That is correct and it's the first step you must take. After that go ahead and implement this method :
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self moveToView];
}
You can also make a switch statement here to see what button was pressed. But since you only have the OK button on the AlertView , it's not necessary.
Hope this helps.
Cheers!
Implement your code in - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex method and also add UIAlertViewDelegate in your class .h file.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSLog(#"The index: %d",buttonIndex);
MainViewController*targetController=[[MainViewController alloc]init];
[self.navigationController pushViewController:targetController animated:YES];
[targetController release];
}
I think it will be helpful to you.
I'm sort of stuck on a UIAlertViewStylePlainTextInput. (My code is too long to post here, but this is the part where the problem exists.) It all sort of works, but the program doesn't wait until the user enters the information before continuing. The "editName" button doesn't change the display in the code below, but the updateDisplay button works fine (if you've pressed the "editName" button before you pressed "updateDisplay"). How can I get everything to sort of halt until the user enters the info (or cancels). Or is there some other lead that will take me where I need to go. (I've been toying with putting the rest of the code in the -(void) alertView, but that just doesn't seem to be the correct way of doing it).
Thanks in advance.
#import "HSTestViewController.h"
#implementation HSTestViewController
#synthesize display;
NSString *newName;
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
newName = [[alertView textFieldAtIndex:0] text];
}
}
- (void) getNewName;
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"You made the High Score List"
message:#"Please enter your name"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Ok", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
- (IBAction)editName:(id)sender
{
[self getNewName];
newName = display.text;
}
- (IBAction)updateDisplay:(id)sender
{
display.text = newName;
}
#end
Add UIAlertViewDelegate to the class. And implement the below delegate method.
OK button index value will be 1 in your case.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex)
{
// call the method or the stuff which you need to perform on click of "OK" button.
}
}
Hope this helps.
why do I get "wait_fences: failed to receive reply" for this code? Is it the way I'm using notification to communicate back to the main thread?
#import "ViewController.h"
#implementation ViewController
#synthesize alert;
#pragma mark - Background Thread Test Methods
- (void) ConfigTasksForBackground:(id)sender{
NSLog(#"ConfigTasksForBackground - Starting");
[NSThread sleepForTimeInterval:6];
[[NSNotificationCenter defaultCenter] postNotificationName:#"ModelChanged" object:self];
NSLog(#"ConfigTasksForBackground - Ending");
}
#pragma mark - Callbacks
- (void) ModelChangedHandler:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"ModelChanged"]) {
NSLog(#"ModelChangedHandler");
[self.alert dismissWithClickedButtonIndex:0 animated:false];
}
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ModelChangedHandler:)
name:#"ModelChanged"
object:nil];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.alert = [[[UIAlertView alloc] initWithTitle:#"Title"
message:#"viewDidAppear"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:nil] autorelease];
[alert show];
[self performSelectorInBackground:#selector(ConfigTasksForBackground:) withObject:nil];
}
#end
Output is:
2011-11-07 15:15:42.730 test_background[6876:13603] ConfigTasksForBackground - Starting
2011-11-07 15:15:48.734 test_background[6876:13603] ModelChangedHandler
2011-11-07 15:15:49.236 test_background[6876:13603] ConfigTasksForBackground - Ending
wait_fences: failed to receive reply: 10004003
There is an obvious problem here. You are posting the notification from the background thread (which is fine) which means the notification handler ModelChangedHandler is being called on the background thread. The handler is then dismissing an alert view which must be done on the main thread. Try changing your code to:
- (void) ModelChangedHandler:(NSNotification *) notification {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(ModelChangedHandler:) withObject:notification waitUntilDone:NO];
}
else if ([[notification name] isEqualToString:#"ModelChanged"]) {
NSLog(#"ModelChangedHandler");
[self.alert dismissWithClickedButtonIndex:0 animated:false];
}
}
EDIT: was typing too fast, changed answer to reflect the correct UI objects.
Here's how to get rid of the wait_fences error. Change the line where you dismiss the alertView to use animation as follows:
[self.alert dismissWithClickedButtonIndex:0 animated:YES];
I think wait_fences has something to do with view animation states with alert views but it's hard to know for sure. I do think this should eliminate the error msg though. My other answer doesn't directly get rid of the error but I still recommend it. UI actions should be done on the main thread.
I'm new to the iPhone and I would like to be able to use UIAlertView in a manner similar to the Windows MessageBox() or the MessageDlg() in Delphi.
For example, I have a method that needs to ask the user for confirmation on something, and proceed based on their response.
E.g. (pseudocode):
-(void)doSomething
{
[doStep1];
[doStep2];
var myValue = [getDefaultValue];
if (myValue = nil)
{
if [promptUser(#"No value in setting. Use the default value?")] //UIAlertView here?
{
myValue = #"defaultValue";
}
else
return; // bug out of the routine 'cause we have no value.
}
[doStep3 withValue:myValue];
}
Or, put put it another way- is there a way of using UIAlertView to ask the user a question within a routine as a way of controlling the logic flow of that routine?
There's no reason to subclass UIAlertView at all. That's what delegates are for. All you need is a class (such as your view controller) supporting the UIAlertViewDelegate protocol, and set the UIAlertView's delegate property to that class. You then implement the alertView:clickedButtonAtIndex: method in this class, and the alertViewCancel: method if you want to specifically handle cancellations differently.
You can read more about it in the UIAlertView documentation and in the UIAlertViewDelegate documentation.
I have no idea what MessageDlg() is, but you can certainly subclass UIAlertView and handle the dialog response, based on which button is pressed, e.g.:
Set up the UIAlertView subclass header:
//
// ARReachabilityAlertView.h
//
#import <UIKit/UIKit.h>
#interface ARReachabilityAlertView : UIAlertView <UIAlertViewDelegate> {
}
#end
Set up the UIAlertView subclass implementation:
//
// ARReachabilityAlertView.m
//
#import "ARReachabilityAlertView.h"
#implementation ARReachabilityAlertView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setTitle:#"Error"];
[self setMessage:#"This application won't run without a network connection. Do you want to quit?"];
[self addButtonWithTitle:#"Quit"];
[self addButtonWithTitle:#"Continue"];
[self setDelegate:self];
}
return self;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
exit(0); // quit application if "Quit" is pressed; otherwise, do nothing
}
- (void) drawRect:(CGRect)rect {
[super drawRect:rect];
}
- (void) dealloc {
[super dealloc];
}
#end
Note the alertView:clickedButtonAtIndex: delegate method. This handles the conditionals you use to decide how the application proceeds. You can send an NSNotification from here, or call a method in the application delegate, whatever you want.
In my example, this UIAlertView is instantiated if there is no network connection, and the application is closed if the user clicks "Quit" in the alert view. Otherwise, if the user clicks "Continue" the application keeps running as usual.
Note that the implementation of the subclass requires the drawRect: method be called. I'm not sure if this is a bug or not, since I'd expect the drawRect: method to be called in the super-class; I filed a bug report with Apple on this one, but I haven't heard anything. Comment it out if you want to see what the effect will be — it's kind of interesting.
I believe you're looking to use UIAlertView as a modal alert box (in the sense that you'd like your code to stop running until the user makes a selection). There's no easy way to do this, and it's really recommended that you NOT code for the iPhone in this manner. I think Alex's explanation is a good solution.
To do this, what you can do is to run the mainloop manually. I have not managed to stop the mainloop directly, so I instead run the mainloop for 0.5 seconds and wait until the user responds.
I ran into this question while researching the problem for a C#/MonoTouch user on the iPhone. The sample below is written for MonoTouch/C# but should be trivial to translate to Objective-C
The following function shows how you could implement a modal query with the above approach:
int WaitForClick ()
{
int clicked = -1;
var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps");
x.Show ();
bool done = false;
x.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
clicked = buttonArgs.ButtonIndex;
};
while (clicked == -1){
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
Console.WriteLine ("Waiting for another 0.5 seconds");
}
Console.WriteLine ("The user clicked {0}", clicked);
return clicked;
}
Just a quick tip: if you want a class to be a delegate for more than one UIAlertView, just use tag property to tell who is who:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Clear all" message:#"Are you sure you want to erase everything?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
alert.tag = ALERT_DELETE_TAG;
[alert autorelease];
[alert show];
Delegate methods are called with UIAlertView as first argument, and you can check who's the originator there.
Thanks to #miguel.de.icaza I found my solution like below (part of the code):
#interface MyClass: NSObject <UIAlertViewDelegate>
{
int confirmed;
}
- (BOOL) removeObjectAtIndex:(NSUInteger)index;
#end
#implementation
- (BOOL) removeObjectAtIndex:(NSUInteger)index
{
// delete confirmation alert
confirmed = -1;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Delete confirmation" message:#"Are you sure to delete object" delegate:self cancelButtonTitle:#"Yes" otherButtonTitles: #"No", nil];
alert.tag = 2;
[alert show];
[alert release];
// wait for confirm (0 or 1)
while (confirmed == -1) {
// this is what you need!!!
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
}
if (confirmed) {
[myObjects removeObjectAtIndex:index];
return YES;
}
else
return NO;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (alertView.tag) {
case 1:
// ...
break;
case 2:
if (buttonIndex == 0) // delete confirmed
confirmed = 1;
else // dismiss
confirmed = 0;
break;
default:
break;
}
}
#end