简体   繁体   English

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

[英]Dismissing a UIAlertView in ios 7 not working?

I'm trying to dismiss a UIAlertView before showing another and I found the answer here: iOS dismiss UIAlertView beforing showing another 我试图在显示另一个之前解雇一个UIAlertView,我在这里找到答案: iOS解雇UIAlertView beforing显示另一个

The problem is that this is not working on iOS7 but works on iOS6. 问题是这不适用于iOS7,但适用于iOS6。

This is working in 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];
}

Is there another solution for this? 还有其他解决方案吗?

Your code is not valid in iOS7 because [UIApplication sharedApplication].windows doesn't have reference to UIAlertView since the UIAlertView itself is never added to any window in iOS7. 您的代码在iOS7中无效,因为[UIApplication sharedApplication].windows没有引用UIAlertView因为UIAlertView本身从未添加到iOS7中的任何窗口。

You need to keep reference to your actionSheet, this is best thing you can do. 你需要继续引用你的actionSheet,这是你能做的最好的事情。

You can do this with a reference to https://stackoverflow.com/a/19275311/1262634 : 您可以参考https://stackoverflow.com/a/19275311/1262634来执行此操作:

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

Edit : this is a private API. 编辑 :这是一个私有API。

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

If either of these solutions are too simple for the context of your application I might suggest rethinking your use of alertviews. 如果这些解决方案中的任何一个对于您的应用程序的上下文来说太简单,我可能会建议您重新考虑使用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. 可以帮助您的另一种方法是在完成alertview的生命后实现基于块的回调。 See Simplify UIAlertView with Blocks . 请参阅使用块简化UIAlertView

Another method to keep track of visible UIAlertView instances is possible by using method swizzling: 通过使用方法调配可以实现跟踪可见UIAlertView实例的另一种方法:

UIAlertView+Dismiss.h: UIAlertView中+ Dismiss.h:

#import <UIKit/UIKit.h>

@interface UIAlertView (Dismiss)

+ (void)dismissAllVisibleAlertViews;

@end

UIAlertView+Dismiss.m: 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

This works since UIAlertViews are being shown by calling the show method. 这是有效的,因为通过调用show方法show UIAlertViews The swizzled method then tracks the instance until it gets dismissed via the dismissWithClickedButtonIndex:animated: method. 然后,swizzled方法跟踪实例,直到它被dismissWithClickedButtonIndex:animated:方法解散。 You can then easily dismiss all alert views by calling [UIAlertView dismissAllVisibleAlertViews]; 然后,您可以通过调用[UIAlertView dismissAllVisibleAlertViews];轻松关闭所有警报视图[UIAlertView dismissAllVisibleAlertViews]; .

Xcode 6.4, for iOS8.4, ARC enabled Xcode 6.4,适用于iOS8.4,支持ARC

There are many posts on this topic. 关于这个主题有很多帖子。 None seemed to be the clear solution to me, so I spent a few hours testing and finally have put together a solution that works to solve the OP's problem: 似乎没有一个对我来说是明确的解决方案,所以我花了几个小时进行测试,最后总结出一个解决OP问题的解决方案:

"I'm trying to dismiss a UIAlertView before showing another..." “我试图在展示另一个之前解雇UIAlertView ......”

As the OP stated the ".windows" method will no longer work. 正如OP所说, ".windows"方法将不再起作用。 There are some other ways that I have read about that involve creating a category to UIAlertView and others using notifications; 我还有一些其他的方法,包括为UIAlertView和其他人使用通知创建一个类别; however, they were too complex for me. 但是,它们对我来说太复杂了。

Here is what to do... 这是做什么的......

1) Conform your class to UIAlertViewDelegate. 1)使您的班级符合UIAlertViewDelegate。

In your class' "*.h" file... 在您的班级“* .h”文件中......

@interface YourViewController : UIViewController <UIAlertViewDelegate>

This will allow the UIAlertView object in your class to send messages to the following method: 这将允许类中的UIAlertView对象将消息发送到以下方法:

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

and for the UIAlertView object in your class to receive messages from the following method: 并为您的类中的UIAlertView对象接收来自以下方法的消息:

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

A word to the wise, you do not have to, in some situations conform your class to UIAlertViewDelegate, but it is the safer choice. 对于明智的一个词,你不必在某些情况下将你的类与UIAlertViewDelegate相符,但它是更安全的选择。 It all depends on how you will use your object in your class. 这一切都取决于你如何在课堂上使用你的对象。

2) Declare the UIAlertView objet as a class variable or as a property. 2)将UIAlertView对象声明为类变量或属性。

Some advantages to creating a property is that you can have access to some getters and setters of the object. 创建属性的一些优点是您可以访问对象的某些getter和setter。

As instance variable, in your class' "*.h" file... 作为实例变量,在您的班级“* .h”文件中......

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

//other properties

@end

As property (recommended) in your class's "*.h" file... 作为班级“* .h”文件中的属性(推荐) ...

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

@property (strong, nonatomic) UIAlertView *yourAlertView;

@end

3) Avoid generating multiple references to your UIAlertView object. 3)避免生成对UIAlertView对象的多个引用。

For example, if you have a method that monitors a certain condition and shows the alert, then do not instanciate the UIAlertView object each time. 例如,如果您有一个监视某个条件并显示警报的方法,那么每次都不要实例化UIAlertView对象。 Instead, instantiate it once in -(void)viewDidLoad and use it where you need it. 相反,在-(void)viewDidLoad中将其实例化一次,并在需要的地方使用它。 Otherwise, this will prevent the 否则,这将阻止

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

method from sending the desired message to the correct UIAlertView object. 从所需消息发送到正确的UIAlertView对象的方法。

4) Assign the tag to the UIAlertView object and manipulate the properties to change the title, message, etc. 4)将标签分配给UIAlertView对象并操纵属性以更改标题,消息等。

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

5) Show the UIAlertView object. 5)显示UIAlertView对象。

[self.yourAlertView show];

6) Dismiss before showing changed UIAlertView object. 6)在显示更改的UIAlertView对象之前解除。

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

[self.yourAlertView show];

7) UIAlertView is depreciated in iOS8. 7)UIAlertView在iOS8中折旧。

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

Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) To create and manage alerts in iOS 8 and later, instead use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert. 重要提示:在iOS 8中不推荐使用UIAlertView。(请注意,UIAlertViewDelegate也已弃用。)要在iOS 8及更高版本中创建和管理警报,请使用UIAlertController,其优先级为UIAlertControllerStyleAlert。

In apps that run in versions of iOS prior to iOS 8, use the UIAlertView class to display an alert message to the user. 在iOS 8之前的iOS版本中运行的应用程序中,使用UIAlertView类向用户显示警报消息。 An alert view functions similar to but differs in appearance from an action sheet (an instance of UIActionSheet). 警报视图的功能类似但与操作表(UIActionSheet的实例)的外观不同。

Use the properties and methods defined in this class to set the title, message, and delegate of an alert view and configure the buttons. 使用此类中定义的属性和方法设置警报视图的标题,消息和委托,并配置按钮。 You must set a delegate if you add custom buttons. 如果添加自定义按钮,则必须设置委托。 The delegate should conform to the UIAlertViewDelegate protocol. 委托应符合UIAlertViewDelegate协议。 Use the show method to display an alert view once it is configured. 配置后,使用show方法显示警报视图。

I had the same problem and I didn't wanted to save all possible alert views as properties. 我有同样的问题,我不想将所有可能的警报视图保存为属性。 I found a great alternative 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];
}];

In the same thread, as comment to one of the posts, there is an explanation why the old approach doesn't work in iOS 7: 在同一个帖子中,作为对其中一个帖子的评论,有一个解释为什么旧方法在iOS 7中不起作用:

In iOS7, windows does not contain the alert view windows. 在iOS7中,Windows不包含警报视图窗口。 They are managed by another stack of windows which are not exposed. 它们由另一堆未暴露的窗口管理。

Hope it helps someone else. 希望它可以帮助别人。 :) :)

Code to dismiss all alert view. 用于关闭所有警报视图的代码。 This is PRIVATE API, so your app may be reject by Apple when upload to Appstore: 这是PRIVATE API,因此Apple上传到Appstore时可能会拒绝您的应用:

Class UIAlertManager = objc_getClass("_UIAlertManager");
    UIAlertView *topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];
    while (topMostAlert) {
        [topMostAlert dismissWithClickedButtonIndex:0 animated:NO];
        topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM