7

我试图在显示另一个之前关闭 UIAlertView,我在这里找到了答案: iOS 在显示另一个之前关闭 UIAlertView

问题是这不适用于iOS7,但适用于iOS6。

这适用于iOS6

-(void)closePreviousAlert{
for (UIWindow* w in [UIApplication sharedApplication].windows)
    for (NSObject* o in w.subviews)
        if ([o isKindOfClass:[UIAlertView class]])
            [(UIAlertView*)o dismissWithClickedButtonIndex:[(UIAlertView*)o cancelButtonIndex] animated:YES];
}

有没有另一种解决方案?

4

6 回答 6

4

您的代码在 iOS7 中无效,因为[UIApplication sharedApplication].windows没有引用,UIAlertView因为它UIAlertView本身从未添加到 iOS7 的任何窗口中。

您需要保留对您的操作表的引用,这是您能做的最好的事情。

您可以参考https://stackoverflow.com/a/19275311/1262634来执行此操作:

Class UIAlertManager = NSClassFromString(@"_UIAlertManager");
UIAlertView *alertView = [UIAlertManager performSelector:@selector(topMostAlert)];

编辑:这是一个私有 API。

于 2013-10-23T05:46:42.767 回答
3

与其使用 O(n^2) 方法来关闭警报,不如为警报创建私有属性并通过其合成的 getter 引用和关闭它们可能会更轻量级(并且 iOS 7 有效)。此外,我有时会在警报视图上设置一个标签,并通过它的标签引用它作为一个快速而肮脏的解决方案。

如果这些解决方案中的任何一个对于您的应用程序的上下文来说都太简单了,我可能会建议您重新考虑您对警报视图的使用。太多的应用程序滥用警报视图,在我看来,它们应该非常谨慎地使用——只是为了添加一些不请自来的反馈:)。

可以帮助您的另一种方法是在警报视图的生命完成后实现基于块的回调。请参阅使用 Blocks 简化 UIAlertView

于 2013-10-23T17:41:29.153 回答
1

另一种跟踪可见 UIAlertView 实例的方法是使用方法 swizzling:

UIAlertView+Dismiss.h:

#import <UIKit/UIKit.h>

@interface UIAlertView (Dismiss)

+ (void)dismissAllVisibleAlertViews;

@end

UIAlertView+Dismiss.m:

#import "UIAlertView+Dismiss.h"
#import <objc/runtime.h>

// see http://nshipster.com/method-swizzling/
static inline void swizzle(Class class, SEL originalSelector, SEL swizzledSelector)
{
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod =
    class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

@implementation UIAlertView (Dismiss)

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        swizzle([self class], @selector(show), @selector(xxx_show));
        swizzle([self class], @selector(dismissWithClickedButtonIndex:animated:), @selector(xxx_dismissWithClickedButtonIndex:animated:));
    });
}

+ (void)dismissAllVisibleAlertViews
{
    for (NSValue *value in [self visibleAlertViews])
    {
        id val = value.nonretainedObjectValue;

        if ([val isKindOfClass: [UIAlertView class]])
        {
            [val dismissWithClickedButtonIndex: 0 animated: YES];
        }
    }
}

#pragma mark - Method Swizzling

- (void)xxx_show
{
    [self xxx_show];

    [[self.class visibleAlertViews] addObject: [NSValue valueWithNonretainedObject: self]];
}

- (void)xxx_dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
{
    [self xxx_dismissWithClickedButtonIndex: buttonIndex animated: animated];

    [[self.class visibleAlertViews] removeObject: [NSValue valueWithNonretainedObject: self]];
}

#pragma mark - Cache

+ (NSMutableSet *)visibleAlertViews
{
    static NSMutableSet *views = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        views = [NSMutableSet new];
    });

    return views;
}

@end

这是有效的,因为UIAlertViews通过调用该show方法来显示。然后,swizzled 方法跟踪实例,直到它通过该dismissWithClickedButtonIndex:animated:方法被解除。然后,您可以通过调用轻松关闭所有警报视图 [UIAlertView dismissAllVisibleAlertViews];

于 2015-06-15T13:24:40.127 回答
1

Xcode 6.4,适用于 iOS8.4,启用 ARC

关于这个主题有很多帖子。对我来说似乎没有一个明确的解决方案,所以我花了几个小时进行测试,最后整理出一个可以解决 OP 问题的解决方案:

“我试图在显示另一个之前关闭 UIAlertView……”

正如OP所述,该".windows"方法将不再有效。我读过的其他一些方法涉及为 UIAlertView 和其他使用通知创建类别;但是,它们对我来说太复杂了。

这是做什么...

1) 使您的类符合 UIAlertViewDelegate。

在您班级的“*.h”文件中...

@interface YourViewController : UIViewController <UIAlertViewDelegate>

这将允许您的类中的 UIAlertView 对象将消息发送到以下方法:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex

并让您的类中的 UIAlertView 对象从以下方法接收消息:

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

对聪明人说一句,在某些情况下,您不必这样做,使您的类符合 UIAlertViewDelegate,但这是更安全的选择。这完全取决于您将如何在课堂上使用您的对象。

2) 将 UIAlertView 对象声明为类变量或属性。

创建属性的一些优点是您可以访问对象的一些 getter 和 setter。

作为实例变量,在你的类的“*.h”文件中......

@interface YourViewController : UIViewController <UIAlertViewDelegate>
{
   UIAlertView *yourAlertView;
{

//other properties

@end

作为您班级的“*.h”文件中的属性(推荐) ...

@interface YourViewController : UIViewController <UIAlertViewDelegate>
{
   //other instance variables
{

@property (strong, nonatomic) UIAlertView *yourAlertView;

@end

3) 避免生成对 UIAlertView 对象的多个引用。

例如,如果您有一个监视某个条件并显示警报的方法,则不要每次都实例化 UIAlertView 对象。相反,将其实例化一次-(void)viewDidLoad并在需要的地方使用它。否则,这将阻止

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

方法从将所需消息发送到正确的 UIAlertView 对象。

4) 将标签分配给 UIAlertView 对象并操作属性以更改标题、消息等。

self.yourAlertView.title = @"some title string";
self.yourAlertView.message = @"some message string";

5) 显示 UIAlertView 对象。

[self.yourAlertView show];

6) 在显示更改的 UIAlertView 对象之前关闭。

self.yourAlertView.title = @"some other title string";
self.yourAlertView.message = @"some other message string";

[self.yourAlertView show];

7) UIAlertView 在 iOS8 中被贬值了。

https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAlertView_Class/index.html#//apple_ref/doc/uid/TP40006802-CH3-SW8

重要提示:UIAlertView 在 iOS 8 中已弃用。(请注意,UIAlertViewDelegate 也已弃用。)要在 iOS 8 及更高版本中创建和管理警报,请使用 UIAlertController 和 UIAlertControllerStyleAlert 的首选样式。

在 iOS 8 之前的 iOS 版本中运行的应用程序中,使用 UIAlertView 类向用户显示警报消息。警报视图的功能类似于操作表(UIActionSheet 的一个实例),但在外观上有所不同。

使用该类中定义的属性和方法来设置警报视图的标题、消息和委托并配置按钮。如果添加自定义按钮,则必须设置委托。委托应符合 UIAlertViewDelegate 协议。配置后使用 show 方法显示警报视图。

于 2015-09-15T19:35:56.263 回答
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];
}];

在同一个线程中,作为对其中一篇文章的评论,解释了为什么旧方法在 iOS 7 中不起作用:

在 iOS7 中,windows 不包含警报视图窗口。它们由另一个未暴露的窗口堆栈管理。

希望它可以帮助别人。:)

于 2014-02-05T15:28:27.583 回答
0

关闭所有警报视图的代码。这是 PRIVATE API,因此您的应用在上传到 Appstore 时可能会被 Apple 拒绝:

Class UIAlertManager = objc_getClass("_UIAlertManager");
    UIAlertView *topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];
    while (topMostAlert) {
        [topMostAlert dismissWithClickedButtonIndex:0 animated:NO];
        topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];
    }
于 2014-04-18T09:53:15.907 回答