Dismissing UIAlertViews when entering background state
I was intrigued by Dad's answer (funny username :), and curious why it was down-voted.
So I tried it.
Here is the .m part of a subclass of UIAlertView.
Edit: (Cédric) I have added a way to catch calls to delegate methods and remove the observer then to avoid multiple registrations to the notification center.
Everything bundled in a class in this github repo: https://github.com/sdarlington/WSLViewAutoDismiss
#import "UIAlertViewAutoDismiss.h"
#import <objc/runtime.h>
@interface UIAlertViewAutoDismiss () <UIAlertViewDelegate> {
id<UIAlertViewDelegate> __unsafe_unretained privateDelegate;
}
@end
@implementation UIAlertViewAutoDismiss
- (id)initWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
self = [super initWithTitle:title
message:message
delegate:self
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil, nil];
if (self) {
va_list args;
va_start(args, otherButtonTitles);
for (NSString *anOtherButtonTitle = otherButtonTitles; anOtherButtonTitle != nil; anOtherButtonTitle = va_arg(args, NSString *)) {
[self addButtonWithTitle:anOtherButtonTitle];
}
privateDelegate = delegate;
}
return self;
}
- (void)dealloc
{
privateDelegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
[super dealloc];
}
- (void)setDelegate:(id)delegate
{
privateDelegate = delegate;
}
- (id)delegate
{
return privateDelegate;
}
- (void)show
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[super show];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
[super dismissWithClickedButtonIndex:[self cancelButtonIndex] animated:NO];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
#pragma mark - UIAlertViewDelegate
// The code below avoids to re-implement all protocol methods to forward to the real delegate.
- (id)forwardingTargetForSelector:(SEL)aSelector
{
struct objc_method_description hasMethod = protocol_getMethodDescription(@protocol(UIAlertViewDelegate), aSelector, NO, YES);
if (hasMethod.name != NULL) {
// The method is that of the UIAlertViewDelegate.
if (aSelector == @selector(alertView:didDismissWithButtonIndex:) ||
aSelector == @selector(alertView:clickedButtonAtIndex:))
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
return privateDelegate;
}
else {
return [super forwardingTargetForSelector:aSelector];
}
}
@end
It works nicely.
It's great, because you can just start using it the same way that you used to use UIAlertView.
I haven't had time to test it thoroughly, but I didn't notice any side effect.
Check instance of UIAlertView when going in background
Remove alert in applicationDidEnterBackground
Add this line in your class
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(enteredBackground:)
name:UIApplicationDidEnterBackgroundNotification
object: nil];
And implement method as well
- (void)enteredBackground:(UIApplication *)application
{
if (mainAlertView && mainAlertView.isVisible)
[mainAlertView dismissWithClickedButtonIndex:0 animated:NO];
}
iPhone app entering background state and presenting a UIAlertView
The best solution I have is to retain a static reference to a UIAlertView, dismiss (with clicked button index -1), release, and then allocate/init a new instance at the same address. This makes sure there's only ever one alert view scheduled or showing. If an alert view is already showing, ignore (or manage) the new request (failsafe popping to root view or some such).
It's not very satisfactory because UIAlertView
s have nothing to do with the workings and shouldn't be static. In my mind at least.
How to properly dismiss a UIAlertView programmatically in iOS 7?
I'm pretty sure this is a bug on Apple's end. I've filed a bug report at https://bugreport.apple.com, please file a duplicate bug report to get Apple to pay attention to it, as that is how Apple assigns priority to bugs.
Dismissing a UIAlertView in ios 7 not working?
Rather than using your O(n^2) approach to close the alert, it would probably be more lightweight (and iOS 7 valid) to create private properties for your alerts and reference and dismiss them via their synthesized getters. Also, I have from time to time set a tag on the alertview and referenced it via its tag as a quick and dirty solution.
If either of these solutions are too simple for the context of your application I might suggest rethinking your use of alertviews. Too many apps abuse alertviews and in my opinion they should be used very sparingly - just to add some unsolicited feedback :).
A different approach that could help you is to implement a block-based callback upon completion of the alertview's life. See Simplify UIAlertView with Blocks.
Remove uialertview in applicationDidEnterBackground
Have a global (AppDelegate property or singleton) where you simply store the pointer to the last alert view displayed (and clear it when done). If the pointer is non-nil, dismiss it in DidEnterBackground or wherever.
Related Topics
Uiview's Border Color in Interface Builder Doesn't Work
Get Date and Time from Apple Server
How to Get Directions in Mkmapview Using a Built in Apple API
Change Width of a Uibarbuttonitem in a Uinavigationbar
Dynamically Increase Height of Uilabel & Tableview Cell
Uitextfield in Uialertcontroller (Border, Backgroundcolor)
How to Convert an Int to a Character in Swift
How to Implement Login/Logout Navigation Using Userdefaults in Swift
iOS 7 Uisearchdisplaycontroller Search Bar Overlaps Status Bar While Searching
Development Team Not Showing in Xcode
How to Find Out Distance Between Coordinates
How to Get Server Response Data in Nsurlsession Without Completion Block
How to Mimic Keyboard Animation on iOS 7 to Add "Done" Button to Numeric Keyboard
Layout Attributes Relative to the Layout Margin on iOS Versions Prior to 8.0
Detect If the Application in Background or Foreground in Swift