进入后台状态时驳回UIAlertViews进入后台状态时驳回UIAlertViews(Dismiss

2019-05-13 06:00发布

苹果建议驳回任何UIAlertViews/UIActionSheets在IOS 4,进入后台状态时,这是为了避免用户的一部分的任何困惑,当他后来将重新启动应用程序。 我不知道我怎么会优雅地关闭所有UIAlertViews一次,不保留对它的引用每次我设置一个...

任何的想法 ?

Answer 1:

我被好奇爸爸的回答 (滑稽的用户名:)和好奇,为什么它向下表决。

所以我想它。

这里是UIAlertView中的一个子类的.M一部分。

编辑:(塞德里克),我添加了一个办法赶上调用委托方法,取下然后观察者避免多次注册到通知中心。

一切都在这个GitHub库中的一类捆绑: 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

它工作得很好。 这是伟大的,因为你可以开始使用它,你习惯用UIAlertView中以同样的方式。

我还没来得及进行彻底的测试,但我没有发现任何副作用。



Answer 2:

我的电话是添加一个类别UIAlertView中添加以下功能:

- (void) hide {
  [self dismissWithClickedButtonIndex:0 animated:YES];
}

并suscribe到UIApplicationWillResignActiveNotification

[[NSNotificationCenter defaultCenter] addObserver:alertView selector:@selector(hide) name:@"UIApplicationWillResignActiveNotification" object:nil];


Answer 3:

一个完全不同的方法是递归搜索。

为您的应用程序委托递归函数

- (void)checkViews:(NSArray *)subviews {
    Class AVClass = [UIAlertView class];
    Class ASClass = [UIActionSheet class];
    for (UIView * subview in subviews){
        if ([subview isKindOfClass:AVClass]){
            [(UIAlertView *)subview dismissWithClickedButtonIndex:[(UIAlertView *)subview cancelButtonIndex] animated:NO];
        } else if ([subview isKindOfClass:ASClass]){
            [(UIActionSheet *)subview dismissWithClickedButtonIndex:[(UIActionSheet *)subview cancelButtonIndex] animated:NO];
        } else {
            [self checkViews:subview.subviews];
        }
    }
}

从applicationDidEnterBackground程序调用它

[self checkViews:application.windows];


Answer 4:

呵呵。 没有试过,但我不知道是否会是有意义的创建UIAlertView中的一个子类,监听此通知和关闭本身如果是的话...

这就会有“自动”,不保留/保持它周围的特征OP请求。 确保注销关于关闭通知(否则热潮!)



Answer 5:

作为在评论中提及某人:接受的答案是不,因为iOS的4.0时,我们有块最好的/干净的! 下面是我如何做到这一点:

UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Alert!" message:@"This alert will dismiss when application resigns active!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification){
        [alert dismissWithClickedButtonIndex:0 animated:NO];
    }];


Answer 6:

我曾与下面的代码解决了这个:

/* taken from the post above (Cédric)*/
- (void)checkViews:(NSArray *)subviews {
    Class AVClass = [UIAlertView class];
    Class ASClass = [UIActionSheet class];
    for (UIView * subview in subviews){
        NSLog(@"Class %@", [subview class]);
        if ([subview isKindOfClass:AVClass]){
            [(UIAlertView *)subview dismissWithClickedButtonIndex:[(UIAlertView *)subview cancelButtonIndex] animated:NO];
        } else if ([subview isKindOfClass:ASClass]){
            [(UIActionSheet *)subview dismissWithClickedButtonIndex:[(UIActionSheet *)subview cancelButtonIndex] animated:NO];
        } else {
            [self checkViews:subview.subviews];
        }
    }
}



/*go to background delegate*/
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    for (UIWindow* window in [UIApplication sharedApplication].windows) {
        NSArray* subviews = window.subviews;
        [self checkViews:subviews];
    }
}


Answer 7:

UIAlertView中获得了有利于UIAlertController的弃用iOS的8。 不幸的是,这被证明是一个棘手的问题,因为接受的解决方案是行不通的,因为苹果明确不支持子类UIAlertController:

该UIAlertController类是打算按原样使用,不支持子类。 这个类的视图层次是私人的,不能修改。

我的解决办法是简单地遍历视图控制器树和罢免你找到所有UIAlertControllers。 您可以通过创建UIApplication的一个延伸,然后调用它在全球范围内的AppDelegate启用此applicationDidEnterBackground方法。

试试这个(斯威夫特):

extension UIApplication
{
    class func dismissOpenAlerts(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController)
    {
        //If it's an alert, dismiss it
        if let alertController = base as? UIAlertController
        {
            alertController.dismissViewControllerAnimated(false, completion: nil)
        }

        //Check all children
        if base != nil
        {
            for controller in base!.childViewControllers
            {
                if let alertController = controller as? UIAlertController
                {
                    alertController.dismissViewControllerAnimated(false, completion: nil)
                }
            }
        }

        //Traverse the view controller tree
        if let nav = base as? UINavigationController
        {
           dismissOpenAlerts(nav.visibleViewController)
        }
        else if let tab = base as? UITabBarController, let selected = tab.selectedViewController
        {
           dismissOpenAlerts(selected)
        }
        else if let presented = base?.presentedViewController
        {
           dismissOpenAlerts(presented)
        }
    }
}

然后在您的AppDelegate:

func applicationDidEnterBackground(application: UIApplication)
{
    UIApplication.dismissOpenAlerts()
}


Answer 8:

直接的方法是持有到UIAlertView中的引用,因此您可以关闭它。 作为petert提及当然你也可以用一个通知做或使用UIApplication的委托方法

applicationWillResignActive:

并不总是意味着你要的背景。 你将要为例子也收到委托调用和通知(你同时获得),当用户得到一个电话或接收和短信。 所以,你必须决定是否用户得到短信和印刷机取消留在你的应用程序应该发生什么。 你可能想确保你的UIAlertView中仍然存在。

所以,我会解雇UIAlertView中,并保存在委托调用的状态,当你真正进入到了后台:

applicationDidEnterBackground:

看一看会话105 - 在developer.apple.com采用多任务处理上提供免费WWDC10的iOS4的。 它变得有趣16:00分

看看这个图表 ,了解应用程序的不同状态



Answer 9:

我有这个我的待办事项清单,但我的第一本能会听出了notifcation UIApplicationWillResignActiveNotification在你喜欢的东西的UIAlertView中的观点(见的UIApplication) -在这里你可以通过编程与删除警报视图:

(void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated

此方法的讨论,甚至提出什么它是在iOS4的!

在iPhone OS 4.0中,你可能想只要你的应用程序移动到后台调用此方法。 当应用程序移动到后台查看警报不会自动解除。 此行为不同于操作系统,其中,当应用程序被终止,他们自动取消以前的版本。 驳回警报视图让你的应用程序有机会保存更改或终止操作,并执行的情况下,你的应用程序后终止任何必要的清理。



Answer 10:

如果你只有一个或两个特定的警告窗口告诉你(像大多数的应用程序),那么你可以创建一个assign伊娃的警告:

@property (nonatomic, assign) UIAlertView* alertview;

然后,在应用程序委托:

[self.viewController.alertview dismissWithClickedButtonIndex:[self.viewController.alertview cancelButtonIndex] animated:NO];

你可以把这个在applicationDidEnterBackground:无论你认为合适或。 它在应用程序退出编程关闭警报。 我一直在做这个和它的伟大工程。



Answer 11:

在UIAlert视图中创建类别

使用http://nshipster.com/method-swizzling/调酒“秀”的方法

跟踪通过保持阵列星期引用显示警报视图中。

- 当你想删除所有数据调用解雇保存的提醒观点和空数组。



Answer 12:

另一种解决方案,基于plkEL的, 答案 ,在当应用程序被置于后台观察者被删除。 如果用户通过按下一个按钮驳回警报,观察者仍然是积极的,但只有等到应用程序置于后台(其中块运行 - 与“无alertView” - 和观察者移除)。

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
                                                message:message
                                               delegate:alertDelegate
                                      cancelButtonTitle:cancelButtonText
                                      otherButtonTitles:okButtonText, nil];
   [alert show];

   __weak UIAlertView *weakAlert = alert;
   __block __weak id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:      [NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification){
   [weakAlert dismissWithClickedButtonIndex:[weakAlert cancelButtonIndex] animated:NO];
   [[NSNotificationCenter defaultCenter] removeObserver:observer];
    observer = nil;
   }];


文章来源: Dismissing UIAlertViews when entering background state