I have a question about how I close and release the custom designed UIAlertView. In my UIAlertView, i'm using the dismissWithClickedButtonIndex function; however, it only closes to the background, it doesn't close in real manner.
Does anyone have a solution for that?
How does it close to the background? I assume you are refering to the pointer of the UIAlertView is still valid after dismissing? In that case you need to [myAlertView release]; to "make it go away completely".
Related
I'm looking at a friend's code and not sure how this works. There's a singleton that talks to a web service to download data. The WebServiceObject is a subclass of NSObject. The download comes from a click on the home page which is a UIViewController.
In the WebServiceObject, when something goes wrong, he does:
UIAlertView *alert = [[UIAlertView alloc] init...];
[alert show];
The alert shows. How does that alert show though since the code that executes it is a non-view object? The reason I'm asking is because I want to remove that alert when the network comes back on. Since the network observing is happening in the WebServiceObject, I'm not sure how to access the UIAlertView object. I thought in other code I've done, that I would do something like
[self.view viewWithTag:NETWORK_ALERT_TAG];
or something to that affect. Is this because the view code is in the model code and instead I should change his code to post a notification to the view code to display the alert instead and grab it that way? Thanks a bunch!
UIAlertView’s -show method creates its own window, overlaid on top of the app’s window, in which to display itself; as such, it isn’t part of the app’s view hierarchy. To hide it, you’ll need a reference to the alert view itself, maybe exposed as a property on your WebServiceObject.
It sounds like you want to have the UIAlertView without any buttons, I found this nice tutorial that presents a "Please Wait Alert"
http://mobiledevelopertips.com/user-interface/uialertview-without-buttons-please-wait-dialog.html
I think it will help you achieve what you want, if you don't want the user to be able to dismiss the alert
I'm running into a problem where 9 times out of ten, when I call UIAlertView's dismissWithClickedButtonIndex:animated:, the delegate method alertView:willDismissWithButtonIndex: is not called. Is anyone else running into this problem? I'm about to file a bug with Apple but I'm curious to see if anyone else has run into this issue and figured out any workarounds.
To ensure a consistent behavior across iOS4 and 5, you could just remove the UIAlertView's delegate just prior to calling its dismissWithClickedButtonIndex:animated: method, then manually invoke the delegate method. e.g.
- (void)somethingDidHappen {
id<UIAlertViewDelegate> delegate = myAlertView.delegate;
myAlertView.delegate = nil;
// now, we know the delegate won't be called...
[myAlertView dismissWithClickedButtonIndex:0 animated:NO];
// ...so we call it ourselves below
[delegate alertView:myAlertView clickedButtonAtIndex:0];
}
(That code isn't tested, but you get the point.)
Delegates of UI objects are only called when the user performs an action. Apple assumes that when you do something from code, you already know what you're doing and you don't need to be informed. That applies to all delegates (scrolling delegate methods of UIScrollView vs. code-scrolling, Table View manipulation, ...)
Anyway, what button index should the delegate be called with?.. there is no one when you dismiss programmatically
According to Why doesn't dismissWithClickedButtonIndex ever call clickedButtonAtIndex? the problem is that a different method is being called. However, that doesn't explain why you get erratic calls. On the devices I tested the dismiss method gets called correctly, so I only redirect it to the click version.
Maybe you should file a bug with Apple if you continue seeing the erratic behaviour.
There are alertView:clickedButtonAtIndex:, alertView:didDismissWithButtonIndex: and alertView:willDismissWithButtonIndex:. The method that you're referring to (clickedButtonAtIndex:) is only called when the user explicitly taps on a button on your alert view (hence 'clicked').
Programmatic calls via dismissWithClickedButtonIndex:animated: to dismiss the alert does not seem to call alertView:clickedButtonAtIndex:.
So, if you need some behavior to be always triggered upon the dismissal of the alert view—whether it was triggered by the user tapping on a button or triggered programmatically—then using the didDismissWithButtonIndex: and willDismissWithButtonIndex: makes more sense.
I'm coding some iPad application, and a strange effect has started to appear.
I use a navigation bar so I can navigate freely through my views. Anyway, in one of these innerviews, I offer the possibility of checking if the user really wants to go back to the main view via an alert view (Just a Yes/no pair of buttons).
Once the user confirms he wants to go back, then I "manually" pop the view, and I navigate to the main view, where the keyboard hides.
BUT, the thing is virtual keyboard acts weirdly. Inside the "inner view", the keyboard is visible 90% of the time (It's normal, there are many UITextFields around). What do I do to hide it whenever I want it to become hidden? I put something like this in the "main viewWillAppear":
[self.view endEditing:YES];
Apparently it hides the keyboard, and when I do:
[[self navigationController] popToRootViewControllerAnimated:YES];
The iPad navigates back, and then the keyboard disappears. No big deal (the first time).
But then I decide to reenter the same view, so the keyboard appears, I do some fancy stuff. Then I decide to abort (with my button), I show the same alert view again, and I confirm I want to go back to the main view (just as before). The code is the same, but then, in the main view, the:
[self.view endEditing:YES];
line, does nothing, and what is worst, I've lost the ability to close the keyboard by code ANYWHERE inside my application, for the whole session.
Why do I know the UIAlertView has something to do? Because if I change the code inside my "Abort button" from this:
alertViewQuestionType=ALERT_ABANDON_TEST;
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"" message:NSLocalizedStringFromTable (#"STR_ABANDON_TEST_WARNING", #"ui_strings", #"") delegate:self cancelButtonTitle:NSLocalizedStringFromTable (#"STR_CANCEL", #"ui_strings", #"") otherButtonTitles:nil] autorelease];
[alert addButtonWithTitle:NSLocalizedStringFromTable (#"STR_ABANDON", #"ui_strings", #"")];
[alert show];
to this:
[[self navigationController] popToRootViewControllerAnimated:YES];
(that is, no confirmation for the user, the user just navigates back, whenever the abort button is pressed), then when the main view reaches the "viewWillAppear" function, the hide keyboard code, works. Not only THAT time, but ALL the time until the end of my app session.
I don't know if my question is 100% clear, but I'll be more than glad to add some extra pieces of code here if someone believes he can shed some light to this mistery...
Greetings!
I've finally solved my problem. I'm more than sure that I could have done better, but for now, even I still don't know "what causes the aforementioned behaviour", I'm more than happy.
The thing is that if I "popped back" a view, FROM inside the UIAlertView delegate code, iOS thinks it's something I shouldn't do, and its internal keyboard management code "becomes out of control". It's as if I'm popping back "too soon", or without having let iOS close whatever keyboard data structures it needed to close.
So a coworker (aleixventa) gave me a hint: "Why don't you delay a bit the 'popback' code, wrapping it inside a "NSTimer structure"?. And that's precisely what I did. My 'pop back' manual code, is now this:
NSTimer* testTimer = [NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:#selector(popViewPorTimer) userInfo:nil repeats: NO];
Having a small function for my popViewPorTimer selector:
-(void) popViewPorTimer
{
[[self navigationController] popViewControllerAnimated:YES];
}
And now, no matter how many times the keyboard is dismissed via "Navigation pop back", it always becomes hidden. YAY!!
For extra bonus, if someone knows why all this happens, it will be a more than welcome piece of info.
I love when I "solve my questions" by myself :)
Well, I must have been completely misled, because I've removed all traces of [self.view endEditing:YES] and/or resignFirstResponder in ALL my .m files and I've discovered 2 things:
1.- They weren't doing ANYTHING. Keyboard auto disappears when needed.
2.- The bug I originally described, is still there.
So, as far as I know, when I just "press back" in the actual UINavigationBar "Back" button (in any inner view), the view, pops back, and if keyboard was present, it disappears. So far so good.
Then some other times, I need to simulate a "Back" press button. I do it with:
[[self navigationController] popViewControllerAnimated:YES];
It works flawlessly, that is, it just pops back, and if keyboard was present, it disappears.
BUUUT, if I write this "manual back" action INSIDE some UIAlertView Delegate I also need (where I deal with two Accept/Cancel buttons), this "manual back action" also pops back to the "parent" view (always, that's OK), but it hides the keyboard ONLY the first time it's called. Succesive calls to "manual back" via this accept/cancel UIAlertDelegate function, render the "keyboard hiding engine" completely unusable for the rest of the session.
I'm plain lost.
I think this scenario should be weird one but i am stuck up with this.
I am having a view lets say View1, which will show one or more alertviews.Alerts are stacked one above the other if they are untouched.
The problem comes here.
If i click the top most alert ,it should take me to a complete new view lets say View2. And it does. Now i am getting the remaining alerts still shown in View2. I do not want this to happen . How can i auto dismiss the pending alerts created from View1 which are currently being shown in View2 ?
Any help or any idea is really appreciated..
Thanks
Try this,
UIAlertView *autoAlertView = [[UIAlertView alloc] initWithTitle:#"Auto-dismissed Alert" message:#"This alert will be dismissed in 5 seconds." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[self performSelector:#selector(dismissAlert:) withObject:autoAlertView afterDelay:5];
[autoAlertView show];
[autoAlertView release];
-(void)dismissAlert:(UIAlertView *)alert {
[alert dismissWithClickedButtonIndex:0 animated:YES];
}
Not quite the answer to your question that you wanted, but...
Why do you have so many alerts? It sounds like you might be overusing them. Apple is quite clear in its Human Interface Guidelines about how you should use UIAlerts:
Avoid creating unnecessary alerts.
These alerts are usually unnecessary
if they:
Merely increase the visibility of some information, especially
information that is related to the
standard functioning of your
application.
Instead, you should design an
eye-catching way to display the
information that harmonizes with your
app’s style.
Update users on tasks that are progressing normally.
Instead, consider using a progress
view or an activity indicator to
provide progress-related feedback to
users (these methods of feedback are
described in “Progress View” and
“Activity Indicator”).
Ask for confirmation of user-initiated actions.
To get confirmation for an action the
user initiated, even a potentially
risky action such as deleting a
contact, you should use an action
sheet.
Inform users of errors or problems about which they can do nothing.
Although it might be necessary to use
an alert to tell users about a
critical problem they can’t fix, it’s
better to integrate such information
into the UI, if possible. For example,
instead of telling users every time a
server connection fails, display the
time of the last successful
connection.
If you're overusing alerts: don't. Then your original question may become moot.
You can dismiss the other UIAlertViews programmatically using:
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
You'll need to store a reference to them at creation to do this.
Thanks, guys! I wrote my own substitute for UIAlertView. I'm putting halftransparent UIView with frame (0, 0, 320, 480) to avoid user interaction while my custom alert still says "Please wait", and above this background view I'm putting this custom alert which is just basic UIView with UIActivityIndicatorView on it
P.S. Don't judge me for my english, i'm russian
I am using the code:
{
randomstatus=0;
msg=[[NSString alloc]initWithFormat:#"Good job, do you want to continue?"];
UIActionSheet *actionSheet=[[UIActionSheet alloc]initWithTitle:msg delegate:self cancelButtonTitle:#"No" destructiveButtonTitle:#"Yes" otherButtonTitles:nil];
[actionSheet showInView:self.view];
[actionSheet release];
[msg release];
}
I don't want to change the code, but I need the "destructiveButton" to be green instead of red. Is this possible, or do i need to use a different button?
There is no "standard" way of changing the appearince of the buttons. Any ways you use will essentially be hacks and may break in the future if Apple change the UIActionSheet component. They may also get your app rejected if they upset the App-Store gods.
I think the most future-proof way of acheiving this is to create your own action sheet class from scratch, ie not subclassing UIActionSheet (as this may break in the future). Although this may be a bit more work up-front than some hack, the extra flexibility you'll gain will come in useful in the future.
This shouldn't be too difficult. You'll need a view which is the background for the action sheet, which you can get by taking a screenshot of a standard UIActionSheet and some photoshopping. Then add your custom buttons as sub-views. A bit of animation for bringing up the view and you're done.
I would aim to have your class implement all the methods the UIActionSheet does, as well as firing off the methods UIActionSHeetDelegate expects. This way you'll be able to substitue it in anywhere you'd otherwise use a native UIActionSheet
Unfortunately there aren't any officially provided methods for customizing UIActionSheet buttons.
However you can access the subviews of the UIActionSheet (which could break in a future iPhone OS update), or add a new view with a button that covers the original destructive action button (once again, this may break).
While not directly related to changing the color of a button on a UIActionSheet, this previous question: iPhone Disabling UIActionSheet buttons demonstrates a few ways you could add custom views to a UIActionSheet.