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

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.

Related

UIAlertViewDelegate not acting as expected

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.

UIAlertView crash by adding clickedButtonAtIndex

I create a class to call UIAlertview show on my screen. I write the UIAlert function in another class. Both these two classes are not my viewController class.
I use this UIAlert, which is a UITextfield inside, to store texts into a plist file.
here is the class to call UIAlert:
#import "Story.h"
#implementation Story
...
+ (void)stage1
{
AlertClass *pointer = [AlertClass new];
[pointer doAlert];
}
here is the class AlertClass.m file:
- (void)doAlert
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
//this makes crash!
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
self.storyFlow.text = [alertView textFieldAtIndex:0].text;
}
Before I add UIAlertViewDelegate in the .h and override the method "clickedButtonAtIndex", it works great. However, I need to store some data from the UITextfield inside the alert view. I get crash and don't know the message it responds as following.
Please help me to solve this problem. Thanks.
[crash pic] https://dl.dropbox.com/u/47381923/crash.tiff
do an NSLog on the text you get back from the Alert View to see whether that is the crash or the subsequent 'self.storyFlow.text = ' is causing it. Perhaps self.storyFlow has not been created yet (with alloc/init)

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

IPhone: How to call AlertView from a Static Function

I have a class as follows
#import "UtilAlert.h"
#implementation UtilAlert
+(void) showAlert:(NSString *)message andTitle:(NSString *)title andDelegate:(UIViewController *) delegate
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
}
#end
The problem is that when call the function with necessary parameters...
[UtilAlert showAlert:#"hello" andTitle:#"hello" andDelegate:self] ;
i get a error: Thread 1: stopped at break point 3;
for the function call from an UIController class
This is not an error. You have a breakpoint in your code, which is the little blue arrow in the left margin of your code. Click the blue arrow again to make it really light blue to turn off the breakpoint.
Also, you should release the alert after showing it before exiting the function or you will leak memory.
Just a wild guess, but your alert object may be released when the function exits if your are working on ARC. In that case, this might work :
+(void) showAlert:(NSString *)message andTitle:(NSString *)title andDelegate:(UIViewController *) delegate {
static UIAlertView *alert;
if(!alert)
alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
}

How to create a method to return UIAlertViews?

I have a question about showing an alert on the screen. The thing is: I have an app with 20 to 30 different screens (nibs) And in each nib I do some checking to see if the user has inserted text in a textedit. And some alert messages are identical to others. Like In 3 nibs there is a text field for the user to enter his age, and the an alert that shows up if he left it blank.
What i want to do is to create a method to show these alerts so I don`t need to have the same alert on different nibs. instead of calling an alert view in each nib, I would call the method and pass what kind of alertview to pop up.
What would be the best way to implement this method?
TIA.
You can just alloc init a new UIAlertView as usual but you have to remember to pass the delegate in.
Here is my method:
- (UIAlertView *)getUIAlertViewWithDelegate:(id)delegate title:(NSString *)title cancelTitle:(NSString *)cancel {
return [[[UIAlertView alloc] initWithTitle:title delegate:delegate cancelButtonTitle:cancel otherButtonTitles:nil] autorelease];
}
All right, I managed to do it. Thanks to all that helped. This is my final solution
I created a common.m classs for some methods that I use in various nibs.
Common.h
#interface MetodosGerais : NSObject <UIAlertViewDelegate>{...}
- (void)getUIAlertViewWithDelegate:(id)delegate title:(NSString *)title cancelTitle:(NSString *)cancel;
Common.m
- (void)getUIAlertViewWithDelegate:(id)delegate title:(NSString *)title cancelTitle:(NSString *)cancel {
if (title == #"Enter your Height"){
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Atention!", #"Atenção!")
message:#"You Should enter Your Height."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] autorelease] show];
}
else if (title == #"Enter your Age"){
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Atention!", #"Atenção!")
message:#"You Should enter your Age."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] autorelease] show];
}
...
and in my classes that I want to use it I did
Common *myAlert = (Common *)[[UIApplication sharedApplication] delegate];
if ([idade.text length] == 0) {
[myAlert getUIAlertViewWithDelegate:self title:#"Enter Your Age" cancelTitle:#"OK"];
}...