进入后台状态时closuresUIAlertViews

Applebuild议在iOS 4中进入后台状态时解除任何UIAlertViews/UIActionSheets 。这是为了避免在稍后重新启动应用程序时对用户造成任何混淆。 我不知道如何能够一次优雅地解除所有UIAlertViews,而不会保留每次我设置一个参考它…

任何想法 ?

我对爸爸的回答很感兴趣(有趣的用户名:),并且好奇为什么它被低估了。

所以我试了一下。

这是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一样使用它。

我没有时间对其进行彻底的testing,但是我没有注意到任何副作用。

我的电话是添加一个类别到UIAlertview添加以下function:

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

并订阅UIApplicationWillResignActiveNotification

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

一个完全不同的方法是recursionsearch。

recursion函数为您的应用程序委托

 - (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]; 

呵呵。 还没有尝试过,但我不知道是否有意义的创build一个UIAlertView的子类侦听这个通知,并closures自己如果是这样…

这将有“自动”没有保留/保持特点OP要求。 确保注销closures通知(否则繁荣!)

正如有人在评论中提到的那样:从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]; }]; 

我已经用下面的代码解决了这个问题:

 /* 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]; } } 

UIAlertView在iOS 8中已被弃用,以支持UIAlertController。 不幸的是,这被certificate是一个棘手的问题,因为接受的解决scheme将无法正常工作,因为苹果明确不支持UIAlertController的子类化:

UIAlertController类旨在按原样使用,不支持子类。 这个类的视图层次是私有的,不能被修改。

我的解决scheme是简单地遍历视图控制器树,并closures所有你发现的UIAlertController。 您可以通过创buildUIApplication的扩展,然后在AppDelegate applicationDidEnterBackground方法中调用它来启用全局。

试试这个(在Swift中):

 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() } 

直接的方法是保持对UIAlertView的引用,以便您可以解除它。 当然,正如petert提到的,你可以用Notification来做,或者在UIApplication上使用委托方法

 applicationWillResignActive: 

并不总是意味着你要背景。 例如,当用户接到电话或接收短信时,您也将收到该代表电话和通知(您将同时收到)。 所以你必须决定如果用户得到一个短信,并按下取消留在你的应用程序会发生什么。 你可能想确保你的UIAlertView仍然在那里。

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

 applicationDidEnterBackground: 

请参阅会议105 – 在developer.apple.com上免费提供WWDC10的iOS4上的多任务处理。 它在16:00分钟变得有趣

查看这个graphics来理解应用程序的不同状态

我有这个在我的TODO列表,但我的第一本能是听取UIApplicationWillResignActiveNotification (见UIApplication)在你有事情像UIAlertView的意见 – 在这里你可以以编程方式删除警报视图:

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

这个方法的讨论甚至可以说明它在iOS4中的作用!

在iPhone OS 4.0中,只要应用程序移动到后台,您可能需要调用此方法。 警报视图不会在应用程序移动到后台时自动解除。 此行为不同于以前版本的操作系统,在应用程序终止时它们被自动取消。 closures警报视图使您的应用程序有机会保存更改或中止操作,并执行任何必要的清理,以防您的应用程序稍后终止。

如果您只显示一个或两个特定的警报窗口(与大多数应用程序一样),那么您可以创build一个assign警报给警报:

 @property (nonatomic, assign) UIAlertView* alertview; 

然后,在应用程序代表:

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

你可以把它放在applicationDidEnterBackground:或者你认为合适的地方。 它在程序退出时以编程方式closures警报。 我一直在做这个,它很好。

在UIAlert视图中创build类别

使用http://nshipster.com/method-swizzling/Swizzle“show ”方法

通过保持数组中的周引用来跟踪警示视图。

– 当你想删除所有的数据调用closures已保存的警报视图并清空数组。

另一个解决scheme是基于plkEL的答案 ,当应用程序放在后台时,观察者被移除。 如果用户按下button来解除警报,观察者仍然是活动的,但是直到应用程序被放到后台(程序块运行的地方 – “无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; }];