open a uiviewcontroller from uialertview button - objective-c

I want to open a UIViewController if a UIALertView Button is pressed.
I have the code for that. However, the uiviewcontroller is not being opened :(
I am sure the uialertview is working fine and all. and the code for the uiviewcontroller is fine as well. (it works when called from other places).
Any help ?
Thanks.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) //Yes, Sign Me Up!
{
NSLog(#"0");
ViewerWebController *web = [[ViewerWebController alloc] initWithURL:[NSURL URLWithString:#"http://www.funimation.com/"]];
[web setShowToolbar:YES];
[self.navigationController pushViewController:web animated:YES];
[web release];
}
else if (buttonIndex == 1) //Remove from List
{
NSLog(#"1");
[[NSUserDefaults standardUserDefaults] setBool:false forKey:#"subscribeButtonOption"];
[_tableView reloadData];
}
else if (buttonIndex == 2) //"Maybe Later"
{
NSLog(#"2");
}
}

The alert view doesn't have a navigation controller. You would need to keep a reference to the navigation controller you want to push the view controller on to.

This may work..
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 0)
{
YourRootNavigationController *navController = [YourRootNavigationController sharedInstance]; // singleton
[navController pushViewController:YOUR_CONTROLLER animated:YES];
}
else
{
NSLog(#"cancel");
}
}

Use didDismissWithButtonIndex rather clickedButtonAtIndex.
The former is invoked after the UIAlertView has been removed from the screen hierarchy, while the latter occurs while the UIAlertView is still on screen. While on screen, UIAlertView alters the nature of the app; that means bad things happen when trying to push views to the nav controller.
This misuse of clickedButtonAtIndex seems to be common misinformation floating around the internet and StackOverflow. Cost me hours of frustration.

Related

Unexpected interface name 'name':expected expression message

I'm at a stage in my coffee order app where I have a UIAlertView pop up from a DetailViewController asking a yes/no to proceed. The 'yes' goes to the next View Controller, which is fine, but the 'no' also goes to the same view controller, but I just want it to return to the DetailViewController, to give the user the option to change their order. I'm using if statements as you can see in the code, but the following code comes up with the "Unexpected interface name 'DetailViewController':expected expression message"
I am new to this, a student learning, and while there are tutorials out there, this one piece of code in my second 'if' statement for buttonIndex ==1 should be correct according to a few solutions on this site, but for some reason, I'm missing something here. I'm using XCode v7.0.1, and am also having difficulty finding up to date solutions for this version.
(note I am aware of the deprecated code for the UIAlertView, but it is working)
Here is the code, appreciate some help:
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
#synthesize YourOrder;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.DetailTitle.text = _DetailModule[0];
self.DetailDescription.text = _DetailModule[1];
self.DetailImageView.image = [UIImage imageNamed:_DetailModule[2]];
self.navigationItem.title = _DetailModule[0];
self.YourOrder.text = #"";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (IBAction)addItem:(id)sender {
self.YourOrder.text = [NSString stringWithFormat:#"%# \n %#",
self.YourOrder.text, [sender currentTitle]];
}
- (IBAction)alertView:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Send Order" message:#"Are you happy with your order?" delegate:self cancelButtonTitle:#"Yes" otherButtonTitles:#"No",nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// the user clicked Yes
if (buttonIndex == 0)
{
// do something here...
}
// the user clicked No - need to write code to return a 'no' click to the DetailViewController to try again.
if (buttonIndex == 1)
{
[self presentViewController:DetailViewController animated:YES completion:nil];
}
}
#end
I have also tried:
if (buttonIndex == 1)
{
DetailViewController *detailView = [[DetailViewController alloc] init];
[self presentViewController:detailView animated:YES completion:nil];
}
but it still goes to the same View controller and I see the "Warning: Attempt to present on whose view is not in the window hierarchy!" error message.

UIAlertView button to display viewController

I've been looking all over the internet for a solution to this problem, yet to find one that I can understand. So here it goes.
I have my iOS application, on which on the first launch of the application, will display a UIAlertView. I want one of the buttons to send the user to a new viewController to view some essential information.
I have gotten my UIAlertView configured properly, here's the code for the actionSheet:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
//Code to open a new viewController???
}
if (buttonIndex == 1)
{
//User can exit the application if they do not wish to continue
exit(0); }
}
}
I have a viewController created named webViewViewController, that's what I want users to reach when they tap the first button. Any ideas on how to do this? I have ARC disabled, other 'solutions' i've come across keep giving me errors.
Thanks all, would appreciate some guidance here.
If your current viewcontroller is in a Navigation Controller:
UIViewController *myViewController = [[UIViewController alloc] init];
myViewController.title = #"My First View";
//to push the UIView.
[self.navigationController pushViewController:myViewController animated:YES];
And never use exit(0)!
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
NewViewController *controller=[[NewViewController alloc]initWithNibName:#"NewViewController" bundle:nil];
self.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentViewController:controller animated:YES completion:nil];
}
drasick has given sufficient answer but if you need to use model view controller refer above.
Use:
UIViewController *yourViewController = [[UIViewController alloc] init];
[self.navigationController presentModalViewController:myViewController animated:YES];
to push a modalViewController.(This is depriciated in iOS 6, but will work)

confirmation before open in safari

Im trying to add a UIAlertView to warn the user that the link will open in Safari. The user can then choose OK(open the url) or cancel which should just close the alert and return to the links.
I have three different UIButtons which has 3 different URLs.
Right now ive added a IBAction to all buttons and all buttons has Tags (which i think i can use somehow :D). I guess - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex: delegate will be good to use to..
My question: how should the UIAlertView know what URL to open i user clicks ok?
I suggest that you use a subclass of UIAlertView that is able to track some more properties along. I do this in all my projects and it is much simpler.
One solution to do this would be to subclass UIAlertView to MyAlertView and add a #property(nonatomic, retain) id userInfo; or #property(nonatomic, retain) NSURL* urlToOpen. Thus you can attach custom data to your UIAlertView and retrieve it in the delegate method to do whatever you need with it.
Another solution, and my preferred one actually, is to add Objective-C blocks support to UIAlertView, to be able to use UIAlertView using the blocks API instead of using a delegate. This is particularly useful if you use multiple UIAlertViews in the same class and with the same delegate, as using a single delegate to handle the different instances is a mess.
I personally use this technique all the time, as it also makes my code more readable by having the code that executes when the button is tapped right next to the code that shows the alert, instead of having it at a complete different places when you use delegate methods.
You can look at my OHAlertView subclass here on GitHub that implement this already. The usage is really simple and allow you to use blocks for each alert view instead of a common delegate, see below.
Usage Example
-(void)confirmOpenURL:(NSURL*)url
{
NSString* message = [NSString string WithFormat:#"Open %# in Safari?",
url.absoluteString];
[OHAlertView showAlertWithTitle:#"Open URL"
message:message
cancelButton:#"No"
okButton:#"Yes"
onButtonTapped:^(OHAlertView* alert, NSInteger buttonIndex)
{
if (buttonIndex != alert.cancelButtonIndex)
{
// If user tapped "Yes" and not "No"
[[UIApplication sharedApplication] openURL:url];
}
}];
}
Then each button can have its own action:
-(IBAction)button1Action
{
[self confirmOpenURL:[NSURL URLWithString:#"http://www.google.com"]];
}
-(IBAction)button2Action
{
[self confirmOpenURL:[NSURL URLWithString:#"http://www.stackoverflow.com"]];
}
Or you can have a common IBAction for all your buttons opening URLs:
-(IBAction)commonButtonAction:(UIButton*)sender
{
NSUInteger tag = sender.tag;
NSString* urls[] = { #"http://www.google.com", #"http://www.stackoverflow.com" };
NSURL* buttonURL = [NSURL URLWithString: urls[tag] ]; // in practice you should check that tag is between 0 and the number of urls to be sure, that's just an example here
[self confirmOpenURL:buttonURL];
}
Solved it like this:
added a tag when creating the UIAlertView. Like this:
- (IBAction)PressedButton {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Link"
message:#"Want to open in safari?"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
message.tag = 2; //different tag for each button
[message addButtonWithTitle:#"Cancel"];
[message show];
}
Then when - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex delegate was thrown I did this:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == alertView.cancelButtonIndex){
if (alertView.tag == 1)
{
//go to URL1
}
else if (alertView.tag == 2)
{
//go to URL2
}
else if (alertView.tag == 3)
{
//go to URL3
}
}
}
Your button action method should have a signature like this:
-(void)doSomething:(id)sender;
whereby sender will be the button. Based on this you could find out which URL is meant.

ModalViewController Without Dimming / Disabling current viewcontroller

I am displaying aNavController as a modalViewController in a specific frame CGRectMake(40,50, 400, 500). Which is working fine. Now I have a button in self (viewcontroller on which modalViewController is presented), on pressing that button I need to display some message on aNavController. But problem is when I am presenting a modalViewController. Whole screen area got dimmed/disabled. So, not able to touch/click that button in self.
Here is my code to present a view controller. I thought, I am missing something here. Please Help. Thanks in advance.
aNavController.modalPresentationStyle = UIModalPresentationFormSheet;
anavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:aNavController animated:YES];
aNavController.view.superview.frame = CGRectMake(40,50, 400, 500);
presentModalViewController create a modal dialog. When modal view controller is up, users can't do any thing on parent view until the the modal view is dismissed.
The problem is you're instantiating a UIAlertView at the same time as the presentModalViewController call your modal view in UIAlertView's delegate method clickedButtonAtIndex.
Like so:
- (IBAction)clickedMyButton:(id)sender
{
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle: #"Title"
message: #"Message"
delegate:self
cancelButtonTitle:#"Close Button"
otherButtonTitles:#"Modal Button", #"Some Other Button", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"User Selected Cancel");
}
else if (buttonIndex == 1) {
NSLog(#"Modal Button Clicked");
aNavController.modalPresentationStyle = UIModalPresentationFormSheet;
anavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:aNavController animated:YES];
aNavController.view.superview.frame = CGRectMake(40,50, 400, 500);
}else {
NSLog(#"Some Other Button Clicked");
}
}
Or, if you wish for your UIAlertView to show on top of your navigation controller, ignore the above and simply wait to call your alert until the navigation controllers - (void)viewDidAppear:(BOOL)animated method.
In addition, I recommend you change your frame to stay within the bounds of the screen unless absolutely necessary. ex: CGRectMake(40, 50, 320, 480);
Finally, I am able to do workaround the things which work same way as a UIModalPresentationFormSheet.
I added the aNavController as a subview to the [[UIApplication sharedApplication] keyWindow] and which solves my all the problems.
Thank you all for your comments.

alertView:clickedButtonAtIndex: causes program closing

I have this piece of code which allocates 2 UIAlertView :
promptConnexion = [[UIAlertView alloc] initWithTitle:#"Connexion"
message:#"\n\n\n"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
promptConnexion.tag = 1;
promptInscription = [[UIAlertView alloc] initWithTitle:#"Inscription"
message:#"\n\n\n\n\n"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
promptInscription.tag = 2;
and this one which specifies what to do when buttons are pressed :
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 1)
{
if (buttonIndex == 1)
{
NSLog(#"Connexion button OK");
}
}
if (alertView.tag == 2)
{
if (buttonIndex == 1)
{
NSLog(#"Inscription button OK");
}
}
}
In my console I actually get "Connexion button OK" and "Inscription button OK" when I should to.
But right after my program is closing unexpectedly whithout any warning or error in my console.
Moreover, if I don't overload alertView:clickedButtonAtIndex: my UIAlertView is just closing, my app still runs correctly, but my buttons do nothing else (obviously).
I also wrote this code :
and showed my 2 UIAlertView this way :
[promptConnexion show];
[promptConnexion release];
and :
[promptInscription show];
[promptInscription release];
and overloaded alertView:didDismissWithButtonIndex: too :
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[alertView release];
}
What am I doing wrong?
Here is your problem;
[alertView release];
You don't want to be doing that at all. In fact if that is all you are doing inside the method, you can remove the method completely as well. This is causing a double release of the alert view which you have already released using [promptConnexion release] etc.
One way to detect such things is to run your program with NSZombiesEnabled as that can show you when you try to release an object that is already released.
This code is your problem:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex: (NSInteger)buttonIndex
{
[alertView release]; // Should not be released here!
}
The reason is, you have already released the alertView here:
[promptConnexion release];
[promptInscription release];
You have done your "duty" by releasing the object you have allocated. The alert view object is now under the responsibility of the operating system displaying that alert view, and it will release it when necessary, without any action of your part.
Just remove that code and it should work.
Also, you should read Apple's Memory Management Rules to have a better understanding of this issue
[promptInscription release]; and [promptConnexion release]; already releases the alertViews. You are releasing it and then after accessing the tag for those alert views and then release it again which I think is the reason for crash.
you should not release the alertView in
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
you already release the alertView instances so there is no need to release that..
Try with not release your alertView in below function.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex`
SO your function should be
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
//Put you code here
}
Just do one thing write your code as below
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 1)
{
if (buttonIndex == 1)
{
NSLog(#"Connexion button OK");
}
}
if (alertView.tag == 2)
{
if (buttonIndex == 1)
{
NSLog(#"Inscription button OK");
}
}
}
No need to override clickedButton Index method just remove it