解雇ios 7中的UIAlertView无法正常工作?

时间:2013-10-23 00:00:47

标签: ios objective-c ios7 uialertview

我试图在显示另一个之前解雇UIAlertView,我在这里找到答案: iOS dismiss UIAlertView beforing showing another

问题是这不适用于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];
}

还有其他解决办法吗?

6 个答案:

答案 0 :(得分:4)

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

您需要继续参考您的actionSheet,这是您可以做的最好的事情。

您可以参考https://stackoverflow.com/a/19275311/1262634

来执行此操作
Class UIAlertManager = NSClassFromString(@"_UIAlertManager");
UIAlertView *alertView = [UIAlertManager performSelector:@selector(topMostAlert)];

修改:这是私有API。

答案 1 :(得分:3)

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

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

可以帮助您的另一种方法是在完成alertview的生命后实现基于块的回调。见Simplify UIAlertView with Blocks

答案 2 :(得分:1)

使用方法调配可以实现跟踪可见UIAlertView实例的另一种方法:

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

答案 3 :(得分: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的preferredStyle。

     

在iOS 8之前的iOS版本中运行的应用中,请使用   UIAlertView类向用户显示警报消息。警报   查看功能类似于但在外观上与动作不同   sheet(UIActionSheet的一个实例)。

     

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

答案 4 :(得分:0)

我遇到了同样的问题,我不想将所有可能的警报视图保存为属性。我找到了一个很好的选择here

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不包含警报视图窗口。它们由另一堆未曝光的窗口管理。

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

答案 5 :(得分: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)];
    }