UIAlertView in ARC app - iphone

I have iphone sample application with one button. On tap it calls code:
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"test"
message:#"test"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];
Application has ARC enabled.
The problem is that if I click on OK button in alert, application crashes with EXC_BAD_ADDRESS - probably because of alert is already removed by arc.
What is recommended way to solve this? without adding property to viewcontroller
thanks

My guess is either you haven't implemented the UIAlertViewDelegate methods or that self has gone out of scope.
If you don't care about being alerted when someone dismisses the alert box, change the delegate to nil.
e.g.
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"test"
message:#"test"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];

The delegate property of UIAlertView is declared as a weak reference (indicated by the assign keyword). This means ARC will not increment the retain count and you will need to retain a reference to the delegate object (whether it is self or a separate object). This reference should be maintained for the full life of the UIAlertView.
#property(nonatomic,assign) id /*<UIAlertViewDelegate>*/ delegate; // weak reference
I assume that the reason for this is to prevent a loop and failure to release as in the common case the object creating the UIAlertView will retain a reference to it and be it's delegate so closing the loop and preventing release.
This is probably a common pattern for delegates but I hadn't realised until I hit exactly the same issue. I ran in the simulator with zombie detection enabled and it clearly indicated the reference counts and I saw that it was not being retained by the UIAlertView. That was when I checked the header file.
The answer to this question provides some additional information about delegates on system classes and the assign keyword.
iPhone ARC Release Notes - dealloc on system classes delegates?

Related

UIAlertView and cocos2d memory mangement

I display a UIAlertView above my cocos2d layer.
I release it after I how it.
Is it really gone? Do I have to somehow remove it from my UIView?
If you just do
UIAlertView* alert = [[UIAlertView alloc] initWithTitle...];
[alert show];
[alert release];
then there's no need to worry about it. However, if you set the alert's delegate to some object, make sure that object still exists when the user taps a button in the alert - otherwise your app will crash when the alert will try to call alertView:didDismissWithButtonIndex: delegate method.

Objective C - Making UIAlertView wait for user input?

I have a UIAlertView set up with a textfield like so:
//***first set of code***
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"User Input Required" message:#"Please enter data into the field" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[alert addTextFieldWithValue:nil label:#"[Enter Text]"];
[[alert textField] becomeFirstResponder];
[alert show];
[alert release];
//***second set of code***`
How can I make it so that the user is required to click a button (I have that method already set up to send the input to a string) BEFORE any of the 'second set of code' is fired off?
I need that second set of code to be contained in the same section as the alert (so I can't just run it within the 'dismissWithClickedButtonIndex' method) and that second set of code is using the string obtained from the user input, so that is why I don't want that code to run prior to the user clicking a button.
Don't you just love it when people say "don't do it that way"... and then never give you any good/correct way you SHOULD be doing it.
Thanks.
You can't do that. show message in UIAlertView won't stop for user input. Associated delegates will need to handle the code you are planning to put in //***second set of code*** section.
Having said that, let me give you some advice. addTextFieldWithValue message is an undocumented API feature. Do not use it. It used to be a long time ago that approval process from Apple for you APP would let you pass even if your application used that addTextFieldWithValue message. But nowadays that does not happen anymore. Your application will be automatically rejected if it is using that undocumented feature. Here is a blog entry on the topic.
Hope it helps.

Close UIAlertView and Replace with Another

I'm running an application that requires LocationServices be enabled. I'm checking if they are by making a call to the service and catching the error. In the error case, I want to pop up an alertview notifying the user to activate location services. I have another AlertView open already when this test happens. I want to close that one and give the user the dialog box I mentioned previously.
Currently, I have
case kCLErrorDenied: // CL access has been denied (eg, user declined location use)
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"NOTICE"
message:#"Sorry, this application needs your location. Please select 'Allow' when asked to use your current location. You don't need to be on or near the trail."
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"EXIT"];
[alert show];
[alert release];
//exit(0);
break;
This causes the app to just exit. I had an NSLog output in there so I know it gets to this case.
here you are specifying delegate:self, then it searches for alert handlers declared at UIAlertViewDelegate and when it doesn't find it crashes.
So you should define
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
in your class.
Also you can implement other methods of UIAlertViewDelegate which will help you in your required task.
You need to keep track of the previous alert with an instance variable, and call the method to dismiss that previous dialog before showing the new one. You also need a delegate handler for the alert.

UIAlertView -show causing a memory leak

I'm relatively new to iPhone Development, so this may be my fault, but it goes against what I've seen. :)
I think that I'm creating a UIAlertView that lives just in this vaccuum of the 'if' statement.
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(!data)
{
// Add an alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Unable to contact server"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
NSLog(#"retain count before show: %i", alert.retainCount);
[alert show];
NSLog(#"retain count before release: %i", alert.retainCount);
[alert release];
NSLog(#"retain count after release: %i", alert.retainCount);
return nil;
}
However, the console logs baffle me.
retain count before show: 1
retain count before release: 6
retain count after release: 5
I've tried also adding:
alert = nil;
after the release. That makes the retain count 0, but I still show a leak. And if it helps, the leak's Responsible Frame is UIKeyboardInputManagerClassForInputMode. I'm also using OS 4 Beta 3.
So anyone have any ideas how a local UIAlertView's retain count would increment itself by 5 when calling -show?
Thanks for your help!
This makes some sense if you realize that [alert show] doesn't immediately put the alert up on screen. I think what happens is that the [alert show] adds the alert to some queue somewhere in the system which retains it. It won't actually be shown until you return from this function and get back to the event loop. When it eventually gets dismissed those retain counts will get decremented and it will be released then.
If you were to log messages from UIAlertView's delegate routines, such as didPresentAlertView, I'll bet that doesn't happen until after your function ends, after you've "released" the alert. Release doesn't always mean deallocate, it is just relinquishing ownership. It only causes a dealloc if there are no owners left.
I highly doubt this is a memory leak. The alert view is just getting shown: it is getting added to the window, etc: which all retain what they own. I bet you that if you check once it has been closed, it won't exist anymore.
My guess would be that this is related to the beta sdk. There are many errors/bugs in the betas. I would suggest checking it with the 3.1.3 or 3.2 sdk.

Bug in AlertView on iPhone?

I write a piece of code to "do something->show alert1->do something->show alert2".
//do something
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Alert 1"
message:nil
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
//do something
UIAlertView *alert2 = [[UIAlertView alloc]
initWithTitle:#"Alert 2"
message:nil
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert2 show];
[alert2 release];
And suddenly a strange thing happened to multiple AlertViews: It shows "Alert 1"->"Alert 2"(Press 'OK')->"Alert 1". Why "Alert 1" shows again? I haven't written any delegate method yet. Maybe a bug?(Thanks to cobbal, alert1 is still there when alert2 appears.)
I find -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex works well. Is the delegate method a common way to show multiple alertViews?
I would guess that alert 1 is shown and then covered by alert 2 since show isn't modal. When alert 2 is closed, alert 1 is still open.
To your second question, alertView:didDismissWithButtonIndex: may work better, but I haven't actually tested that.
The delegate is so that you can be notified when the alert is dismissed, and which button was used to dismiss it. It doesn't impact whether the alert is dismissed at all.
The alert will remain visible until it is dismissed either by you tapping a button (if any - they are not required) or you call either [UIAlertView dismissWithClickedButtonIndex:animated] or the (undocumented) dismiss method of the alert instance.
It looks like (as Cobbal suggested), alert 2 is popping up over alert 1, you dismiss alert 2, and alert 1 remains there (until it itself is dismissed).
Is there a particular reason you want to show a new alert while another is still showing? Perhaps some more context would help us to get to the root of the issue, which I suspect may be a design issue.
[edit] coming back to this and reading again, I wonder if what you are asking about with the delegate method is whether you should be showing alert 2 from there? In which case that's probably what you want - whether directly or indirectly. By indirectly I mean that you may have some state set elsewhere that determines whether alert 2 should be shown (or the circumstances that lead to it). That state (a flag, perhaps) could be set when you show the first alert, and cleared when the alert is dismissed (from the delegate method).
The reason this happens is because UIAlertView doesn't block while it's showing. Any code written after showing an alertview will run straight after the alert is shown.
What you should have is two different methods. One that does something and then shows an alert, and then another that does something and shows another alert.
Kick off the first method to do something and show an alert, and then hook into the alert's delegate method, and when you get the callback from the alertview, run the other method.
This way, the second part of the process won't happen until the user has pressed OK on the alert in first part of the process.