UIAlertViewDelegate not acting as expected - iphone

I have a very simple process running where after each round of a simple game the scores are calculated, labels updated and all the normal, very simple stuff. I have a UIAlertView that informs the player of how s/he performed. I use a UIAlertViewDelegate to postpone all the updates, resetting of controls etc. till after the UIAlertView is dismissed. The methods are [startNewRound],[startOver] and [updateLabels]. It's fairly obvious what they all do. Anyway, when the user hits round ten, I've made another UIAlertView that informs the player that the game has ended and shows the overall score. Again, I hoped to use a delegate to postpone the resets till after the AlertView is dismissed. The only problem is, with the endGame AlertView, it seems to be using the first AlertView's delegate method causing the game to continue with a new round and not start from the beginning. I hope this makes sense. Anyway, here are snippets of my code.
if (round == 10){
UIAlertView *endGame = [[UIAlertView alloc]
initWithTitle: #"End of Game"
message: endMessage
delegate:self
cancelButtonTitle:#"New Game"
otherButtonTitles:nil];
[endGame show];
}
else {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle: title
message: message
delegate:self
cancelButtonTitle:#"Next"
otherButtonTitles:nil];
[alertView show];
}
And then the delegate methods:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[self startNewRound];
[self updateLabels];
}
- (void)endGame:(UIAlertView *)endGame didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[self startOver];
}
So there it is. As I mentioned, the endGame AlertView appears to be using alertView's delegate, thus not activating the [self startOver] method. All the methods are working, it's just the AlertView is using the incorrect delegate method. Regards, Mike

Change your code like this,
if (round == 10){
UIAlertView *endGame = [[UIAlertView alloc]
initWithTitle: #"End of Game"
message: endMessage
delegate:self
cancelButtonTitle:#"New Game"
otherButtonTitles:nil];
endGame.tag = 111;
[endGame show];
}
else {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle: title
message: message
delegate:self
cancelButtonTitle:#"Next"
otherButtonTitles:nil];
alertView.tag = 222;
[alertView show];
}
and delegate method as,
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if(alertView.tag == 111)
{
[self startNewRound];
[self updateLabels];
}
else if(alertView.tag == 222)
{
[self startOver];
}
}

You cant have two delegate method for dismisswithbuttonindex, you need to handle this situation with tag.
Give both alert view a different tag and check it on delegate object. Thus you can differentiat the both alert view.

Related

EXC_Bad_Request "only" after calling the uialert 3 or more times

I am a newbie in objective c;
I am getting an error at creating a UIAlertview instantiation statements (UIAlert * myAlert, they are in separate scopes)
I have referred the following stackoverflow entries such as This, this, this too and much more research over the internet.
I am unable to get a break through
Following are my alert calls
This is my view controller code where I have put up the "UIAlertViewDelegate"
#import <UIKit/UIKit.h>
#interface gameFirstViewController : UIViewController<UIAlertViewDelegate>
#end
This is my class declaration
#import <Foundation/Foundation.h>
#interface GameLogic : UIView
//all sorts of various non relevant property declarations
#end
Here is my implementation for the alerts
//action to take when an alert is shown
- (void)alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger) buttonIndex
{ NSLog(#"OK Tapped");
NSUserDefaults *MySettingsData = [NSUserDefaults standardUserDefaults];
row= [MySettingsData integerForKey:#"Row_count"];
col = [MySettingsData integerForKey:#"Column_count"];
if(buttonIndex==0)
{
for(int i=0;i<row;++i)
{
for(int j=0;j<col;++j)
{
myarr[i][j]=0;
}
}
if(_TimerStatus ==1)
{
[mainTimer invalidate];
mainTimer=nil;
_TimerStatus=0;
}
[self super_reset];
[self setNeedsDisplay];
NSLog(#"Game reset");
return;
}
}
//my usage of the alerts at 2 different places
UIAlertView *myAlert = [[UIAlertView alloc]initWithTitle: #"GAME OVER"
message:#"You clicked on a mine, tap on ok to reset"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[myAlert performSelectorOnMainThread:#selector(show)
withObject:nil
waitUntilDone:YES];
UIAlertView *myAlert = [[UIAlertView alloc]initWithTitle: #"You Won! Whoo Hoo"
message:#"You have successfully dodged every minefield"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[myAlert performSelectorOnMainThread:#selector(show)
withObject:nil
waitUntilDone:YES];
I am not sure where I am going wrong, any help would be great!
Thanks.
The way you are creating the UIAlertView is not safe in ARC. It's fine if you use the object right away, but you're passing it the performSelectorOnMainThread method. ARC may dealloc your myAlert variable by the time the main thread gets to perform the selector. That's likely why you're seeing the EXC_Bad_Request.
Either make myAlert a strong property, so it survives, or delay the creation of the UIAlert until the main thread is able to call the show method. You can do that like this:
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:#"GAME OVER" message:#"You clicked on a mine, tap on ok to reset" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil] show];
});
Note: I removed your double nil for the titles. I don't think that would make a difference, but just in case.

Executing a snippet of code in the AlertView OK button declaration

in my Alert View, there is two button, OK and Cancel. When the user click the OK button, the delegate method dismissWithClickedButtonIndex:animated get called, and if the index is 0, then i get called to a method to execute some code:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Are you sure you want to exit"
delegate:self cancelButtonTitle: #"OK"
otherButtonTitles: #"Cancel",nil];
[alert show];
[alert release];//release the reference
Delegate method:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
if (buttonIndex==0) {
[self aMethod];
}
}
-(void)aMethod{
//Some useful code
}
Now, what i want to instead of all this, is to execute the code of the aMethod method in the AlertView directly, without referring to A delegate method and a method which get called, something like that:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Are you sure you want to exit"
delegate:self cancelButtonTitle: #"OK" //Put here some useful code
otherButtonTitles: #"Cancel",nil];
Is it possible?
Unfortunately this is not possible at this time (iOS 5.1). The AlertView class does not support blocks.
I made a pair of UIAlertView and UIActionSheet subclasses that do exactly that. Grab them here:
https://github.com/rydermackay/RMActionSheet
Use them like this:
RMAlertView *alertView = [RMAlertView alertViewWithTitle:#"Alert!" message:nil];
[alertView addButtonWithTitle:#"OK"
action:^{
NSLog(#"OK");
}];
[alertView addCancelButtonWithTitle:#"Cancel"
action:nil];
[alertView show];
EDIT:
From your comments it sounds like you're not familiar with blocks. Read this now. Seriously.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html
This is a good one too:
http://www.mikeash.com/pyblog/friday-qa-2009-08-14-practical-blocks.html

Multiple alertViews create error

Hello and good afternoon, I'm having some issues here, and to be honest, I don't understand
I have to create different alertViews for the same screen with different messages, most of these alerts only have 1 button, but there's this one to delete that needs 2 buttons, the thing is that, since the others have only 1 button, when I created the 2 button screenview and I added the (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex method, I have some problems
some code here
- (IBAction)saveInfo{
if (med.text.length ==0) {
UIAlertView *alertViewError = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ERROR",#"")
message:NSLocalizedString(#"EMPTY1",#"")
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alertViewError show];
[alertViewError release];
}
else if(medicamento.text.length >= 41){
[self lenghtError:40:NSLocalizedString(#"TF_MED",#"")];
}
else if (med.text.length ==0 || descripcion.text.length == 0) {
UIAlertView *alertViewError = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ERROR",#"")
message:NSLocalizedString(#"EMPTY2",#"")
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alertViewError show];
[alertViewError release];
}
else if (descripcion.text.length >= 41){
[self lenghtError:40:NSLocalizedString(#"TF_DESCRIPCION",#"")];
}
else{
[self insertDictionary];
UIAlertView *alertViewAcept = [[UIAlertView alloc] initWithTitle:#""
message: NSLocalizedString(#"ACCEPT_MSG",#"")
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alertViewAcept show];
[alertViewAcept release];
[self.navigationController popViewControllerAnimated:YES];
}
}
- (IBAction)cancelData{
UIAlertView *alertViewCancel =
[[UIAlertView alloc] initWithTitle: NSLocalizedString(#"BT_DELETE_MED",#"")
message: NSLocalizedString(#"MSG_DELETE_MED",#"")
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: #"Cancel", nil];
[alertViewCancel setTag:999];
[alertViewCancel show];
[alertViewCancel release];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 999) {
if(buttonIndex==0){
[self.Bayer_DB_obj deleteRowWithKeyValue:[NSString stringWithFormat:#"%d",IdMed] onKeyName:#"id_ctl_med" onTable:#"ctl_med"];
// code to delete here
[self.navigationController popViewControllerAnimated:YES];
}
}
}
So, in the first part, I created some alerts to indicate the user that he/she is making a mistake, in the second part, I need a confirmation before deletion, but here, I need 2 buttons, then, in the 3rd part, I have the method that is been called, I added a tag to my alert to avoid doing this comparison in all the alerts, the problem is that, when you show alertViewAcept, it takes you to the previous view controller, and after you click the ok button (that actually is the cancelbuttontitle) the app crashes without any "error message"
so I'm not sure what I'm doing wrong, please help
My guess the problem is that you set the delegate for the alertViewAcept, and right after you showed the alert, you pop the viewController and so your delegate will get released, which will then give you an error once a button on the alert view is clicked.
You should do this:
UIAlertView *alertViewAcept = [[UIAlertView alloc] initWithTitle:#""
message: NSLocalizedString(#"ACCEPT_MSG",#"")
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
Even better, all your alerts which only have the OK button, do not need a delegate. And in that case you do not even need the tag.

Multiple alertviews in a single view?

I have an Iphone application in which when i am pressing a button it shows an alertview to chose the background.whichever background user is chosing will be played as the background of the audio clips.But now i need to add another alert before i am showing this alert for giving some warning.after that only i need to pop the second one.but i was done that chosing alert in the didappear of that viewcontroller and set it as a Uialertview delegate.and on the button actions i was doing different actions.Can anybody help me on achieving this?
proAlertView *loginav1=[[proAlertView alloc] initWithTitle:#"title" message:#"Choose a Background to play with this program?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Field",#"Beach", #"Stars",nil];
[loginav1 setBackgroundColor:[UIColor colorWithRed:0.129 green:0.129 blue:0.129 alpha:1.0] withStrokeColor:[UIColor colorWithHue:0.625 saturation:0.0 brightness:0.8 alpha:0.8]];
[loginav1 show];
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 0)
{
//[self play];
//moviePlayer.scalingMode=MPMovieScalingModeAspectFill;
if(actionSheet.tag==123)
{
[self backButtonPressed];
}
}
else if (buttonIndex == 1)
{
videoFile = [[NSBundle mainBundle] pathForResource:#"video-track" ofType:#"mp4"];
[self play];
moviePlayer.scalingMode=MPMovieScalingModeAspectFill;
}
how can i include another alert before this is my question?
Initialize first Alertview
UIAlertView *al1 = [[UIAlertView alloc] initWithTitle:#"Warning!" message:#"Warning Msg!!!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
al1.tag=1;
al1.delegate=self;
[al1 show];
Implement Delegate method
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(alertView.tag==1){
// implement button events for first Alertview
if(buttonIndex==1){
//First button clicked of first Alertview
UIAlertView *al2 = [[UIAlertView alloc] initWithTitle:#"Choose BG" message:#"Choose BG?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"1",#"2",#"3", nil];
al2.tag=2;
al2.delegate=self;
[al2 show];
}
}
if(alertView.tag==2){
// implement button events for second Alertview
if(buttonIndex==1){
// First button clicked second Alertview.
}
}
}
Controller Class header
#interface ViewController : UIViewController<UIAlertViewDelegate>{
}
Hope this will fulfill your need !
You can do like this, first display warning message in alertview and when user click OK in alertview then in alertview delegate method write code to display second alertview where user can choose background.

UIAlertView and detemining what is clicked

I have code that when a user hits the end of the game, it prompts them if the would like to play again:
-(void)showAlert
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#" B U S T E D ! "
message:#"Sorry, you busted!\n\nWant to try your luck 1 More Time! ?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"New Game", nil];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 0)
{
//here is where we can close it
}
if (buttonIndex == 1)
{
[self createNewGame];
}
}
Now I want to also do a check when a user first starts the app to see if a prior game file exists and if so ask if they want to continue. I know I can do via:
-(void)priorGameExists
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#" Previous Game Exists ! "
message:#"A previous game currently exists. Would you like to resume that game?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Resumse", nil];
[alert show];
[alert release];
}
But how do I have it go to a new "custom" clickedButtonAtIndex? Am I correct in assuming it has something to do with setting a different delegate? And if so, how would I do that?
You don't necessarily need a different delegate. Read my answer to this question:
iPhone - Several UIAlertViews for a delegate
One solution is to declare some UIAlertView as private class instance like that:
#interface myViewControllerInterface : UIViewController {
#private
UIAlertView *newGameAlert;
UIAlertView *resumeGameAlert;
}
Then in your view controller you can create your alertViews using them:
-(void)showAlert {
newGameAlert= [[UIAlertView alloc] initWithTitle:#" B U S T E D ! "
message:#"Sorry, you busted!\n\nWant to try your luck 1 More Time! ?"
delegate:self cancelButtonTitle:#"Cancel"
otherButtonTitles:#"New Game", nil];
[newGameAlert show];
[newGameAlert autorelease];
}
-(void)priorGameExists {
resumeGameAlert = [[UIAlertView alloc] initWithTitle:#" Previous Game Exists ! "
message:#"A previous game currently exists. Would you like to resume that game?"
delegate:self cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Resumse", nil];
[resumeGameAlert show];
[resumeGameAlert autorelease];
}
And to finish you can make the difference between each alert view using their pointer:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (actionSheet == newGameAlert ) {
//do something
} else if (actionSheet == resumeGameAlert ) {
//do something
}
}
You could use a different delegate but an easier way would be to set the tag property to a unique value. If tag was, say, 10 you'd know it was from the original alert and if it was 20 it would be from the priorGameExits question. (You should probably use constants of course.)
in your clickedButtonAtIndex method test the title of the incoming alertview.
if ([actionSheet.title isEqualToString:#" B U S T E D ! "]) {
// do some busted stuff here
else if ([actionSheet.title isEqualToString:#" Previous Game Exists ! "]) {
// do some previous game stuff here
}
You'll probably want to set those titles using static strings, so you only have the string in one place in your code, but this is basically how you'd do it.