Dismissing Uialertviews When Entering Background State

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 UIAlertViews 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



Leave a reply



Submit