Following are the code for displaying alert in a view controller
-(void)saveProducts {
pData = [[JsonModel sharedJsonModel] prodData];
if ([pData count] == 0 && [self respondsToSelector:#selector(alertView:clickedButtonAtIndex:) ] ) {
alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"No products against this category" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
[self.tblView reloadData];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
[self.navigationController popViewControllerAnimated:YES];
[actInd stopAnimating];
}
}
But in slow network, alert will come slowly. If we click on back button of navigation bar at the mean time, pop the navigation controller and displaying alert in new view controller. But when i clicks on OK, app suddenly crashes with EXC_BAD_ACCESS error.
I also tried
didDismissWithButtonIndex
function instead of
clickedButtonAtIndex
But same error occurs. Please help me
It works normally if we didn't click on back bar button. Problem only arises when first view controllers alert displays in second view controller
EDIT
This is the error report
* -[ProductsListing alertView:didDismissWithButtonIndex:]: message sent to deallocated instance 0x8478280
EDIT
I understand the problem. When I click on back button, my alert delegate deallocates and delegate calling results error. How can I overcome this?
My best guess is that either 'self.navigationController' or 'actInd' have already been released. Also, your 'UIAlertView' leaks memory (unless you're using ARC). Profile the app using Instruments, selecting the "Zombies" tool and see what it comes up with.
I believe you have to change
[alert show];
to
if(self.view.window){
[alert show];
}
This way the alert appears only if the controller(the view) is still on screen.(why let the user see an alert from a previous screen?)
If you want the alert to appear anyway....then the "old" controller must inform the "new" one that a problem occurred...and now its the new controller's job to inform the user.
Or you can try changin this part
[self.navigationController popViewControllerAnimated:YES];
[actInd stopAnimating];
to
if(self.view.window){
[self.navigationController popViewControllerAnimated:YES];
[actInd stopAnimating]; // im not sure where the animation is...so not sure if this shoulb be in here or not
}
From what you described the problem here may be this(a wild guess)
[actInd stopAnimating];
called after the viewController is removed(popped).the actInd may not have a valid memory and hence it crashes
change the method content like this and check
if (buttonIndex == 0) {
[actInd stopAnimating];
[self.navigationController popViewControllerAnimated:YES];
}
Related
I am using XCode 5.1.1 for development purposes and using the iOS simulator to test my app.
I have an action sheet that has Save, Cancel and Delete options. I haven't yet coded the action handling for Save and Delete, but tapping on cancel should go back to the previous screen (I have used navigation controller to move between screens). But tapping on cancel, throws me "ViewController actionSheet:clickedButtonAtIndex:]: message sent to deallocated instance" error, which I am not able to solve. I have hooked up all the elements to their outlets/actions correctly. Below is my code. Please help. (I am trying to display the action sheet when a "return" button is clicked. And in the action sheet, when I tap cancel, the previous screen had to be displayed - I guess this can be done by dismissViewControllerAnimated which dismisses the current controller and displays the previous controller.)
-(IBAction)returnModalAction:(id)sender {
[self dismissViewControllerAnimated: YES completion: NULL];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"What do you want to do with the user values?"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:#"Delete"
otherButtonTitles:#"Save", nil];
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:#"Cancel"];
[actionSheet showInView:self.view];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 2) {
NSLog(#"You have pressed the %# button", [actionSheet buttonTitleAtIndex:buttonIndex]);
}
}
On your method returnModalAction: you are dismissing the view, so the garbage collector will release all the references of self(the view controller) in memory that's why when you try to to show the action sheet [actionSheet showInView:self.view]; you get the error because the reference in memory doesn't exist.
So what you have to do is to perform [self dismissViewControllerAnimated: YES completion: NULL]; when you actually want to display the previous screen, in your case that would be on the actionSheet:clickedButtonAtIndex: method, based on the index of the button.
I need to verify credentials. So the segue is linked from first view controller to second view controller in a sign in button.
When I do the segue without any condition check. the navigation works fine.
But when i control the segue using the code below in first view controller, navigation flow disrupts. When the criterias are met it goes to second view controller but when i try to go back to first view controller through navigation controller the screen turns black.
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if ([userTxt.text isEqualToString:username]&&[passwordTxt.text isEqualToString:password]) {
[self performSegueWithIdentifier:#"signin" sender:nil];
return YES;
}
else
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"INCORRECT" message:#" INCORRECT USER NAME OR PASSWORD" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil , nil];
[alert show];
return NO;
}
}
Try removing the
[self performSegueWithIdentifier:#"signin" sender:nil];
I need to show an UIAlertView before a user leaves a certain view, either by tapping a 'back' navigation bar button or by tapping one of the tab items in the tab bar I have, in order to ask him for confirmation. It would be a two-button alert, a 'Cancel' one to stay in the view, and an 'Accept' one to leave. I need to do this because I have to make the user aware that unsaved changes will be lost if leaving.
I tried to do this by creating and showing the alert view in the viewWillDisappear: method:
- (void)viewWillDisappear:(BOOL)animated
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Exit", #"")
message:NSLocalizedString(#"Are you sure you want to leave? Changes will be discarded", #"")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Cancel", #"")
otherButtonTitles:NSLocalizedString(#"Accept", #""), nil];
[alertView show];
[super viewWillDisappear:animated];
}
But the view is pop anyway, and the alert view is shown after that and app crashes since its delegate is the view controller that has been already pop from the navigation stack... I don't find the way to solve this scenario, can anybody help me?
Thanks!
Showing the alert view when viewWillDissapear won't work, because the view is already dissapearing, it's on its way to be removed.
What you can do, is add yourself a custom action when the back button is pressed, then you decide what to do when the back button is pressed, you can show the alert view, and then in one of the buttons procedd to dismiss the view, something like this:
- (id)init {
if (self = [super init]) {
self.navigationItem.backBarButtonItem.target = self;
self.navigationItem.backBarButtonItem.action = #selector(backButtonPressed:);
}
return self;
}
Then show the alert view when the back button is pressed:
-(void)backButtonPressed:(id)sender
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Exit", #"") message:NSLocalizedString(#"Are you sure you want to leave? Changes will be discarded", #"") delegate:self cancelButtonTitle:NSLocalizedString(#"Cancel", #"") otherButtonTitles:NSLocalizedString(#"Accept", #""), nil];
[alertView show];
}
Now, when the confirmation button in the alert view is pressed, just call:
[self.navigationController popViewControllerAnimated:YES];
Or do nothing if the user cancels
I would be tempted to move the data manipulation you're trying to protect into a modal view controller and handle the validation on whatever action you choose to have dismiss the modal presentation. To me, that's the point of modal: something that has to be completed before interacting with the rest of the app.
As you can see I'm trying to performSegue from Photo Action View Controller to Setting View Controller (UITableViewController).
So I'm performing from PhotoActionViewController directly (not using buttons etc.) because I want to perform this segue when user taps on one option from showing AlertView. Everything works like charm untill I set Class for the SettingsViewController. The segue performs but I can't see any UITableViewCell. How can I get this wor form me?
Here is my code:
- (IBAction)imageViewTapped:(UITapGestureRecognizer *)sender
{
BlockAlertView *alert = [BlockAlertView alertWithTitle:#"New Photo" message:#"Decide what you would like to do with this photo"];
[alert addButtonWithTitle:#"Create New Project" block:^{
// Pushing to New Project Settings Controller
[self performSegueWithIdentifier:#"NPSSegue" sender:self];
}];
[alert addButtonWithTitle:#"Add To Existing Project" block:^{
NSLog(#"Add to existing");
}];
[alert setCancelButtonWithTitle:#"Cancel" block:nil];
[alert show];
}
I'm not posting prepareForSegue as it is empty for this moment and I don't know if anything should be there.
whenever using segue programmatically we need to connect segue through one scene to another scene(viewcontroller) so create a button make it invisible and connect it to the destination scene and in uialertview delegate make button setEnabled:true and before pls set the segue Idetifier thanks and sorry for poor english.......
I am really stumped on this one issue I am having.
So we have an app that allows the user to sync some photos to our server. So I accomplished that with a dispath_async call and it works, however I would like to tell the user that it has finished weather successful or not.
So my question is how do I show the user an AlertDialog box, when I DO NOT know what view they will be on(since it's async I don't want them to have to stay on that ViewController, but move around the app and do other things while that is being uploaded).
I have tried:
[self showAlertView]; but that crashes the app because I am no longer on that view.
Than I tried:
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView* alert = [UIAlertView withTitle ....]; // you get the idea, just create a simple AlertView
[alert show]; // also tried: [alert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO]; here and that didn't work either
});
Oh and LocalNotifications aren't going to work because if they are in the app it doesn't show up(Android has iOS beat on this front, it would be a lot easier to have that just work when the user is in the app too, then I wouldn't have to worry about all of this).
Any ideas on how I can accomplish my goal.
You can use UILocalNotification even if the app is running in the foreground but you will have to handle the notification your self. You can just display an simple AlertView.
Just add this to the app delegate class:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:notification.alertBody message:nil delegate:nil cancelButtonTitle:#"Oke" otherButtonTitles:nil];
[alert show];
}
You can display a modal view on the current controller by accessing the controller through your application's window.
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIViewController *controller = window.rootViewController;
// Use controller to display your window.