UIAlertView firing in ios 7 not working?

I try to reject a UIAlertView before showing another, and I found the answer here: iOS rejects a UIAlertView showing another

The problem is that this does not work on iOS7, but it works on iOS6.

It works in 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 any other solution for this?

+7
ios objective-c ios7 uialertview
source share
6 answers

Instead of using your O (n ^ 2) approach to close the warning, it would probably be easier (and iOS 7) to create private properties for your warnings and links and drop them through their synthesized getters. In addition, from time to time I set the tag in alertview and refer to it through my tag as a quick and dirty solution.

If one of these solutions is too easy for the context of your application, I can suggest rethinking your use of alertviews. Too many warnings about abuse by the applications, and, in my opinion, they should be used very sparingly - just to add unsolicited feedback :).

Another approach that may help you is to implement a block callback after the alertview expires. See Simplify UIAlertView with Blocks .

+3
source share

Your code is not valid in iOS7 because [UIApplication sharedApplication].windows does not have a link to UIAlertView , since UIAlertView itself is never added to any window in iOS7.

You need to keep a link to your ActionSheet, this is the best you can do.

You can do this with a link to https://stackoverflow.com/a/166269/29 :

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

Edit : This is a private API.

+4
source share

Another way to track visible instances of UIAlertView is by using the swizzling method:

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 

This works because UIAlertViews displayed by calling the show method. The swizzled method then tracks the instance until it is rejected using the dismissWithClickedButtonIndex:animated: method. You can then easily discard all warnings by calling [UIAlertView dismissAllVisibleAlertViews]; .

+1
source share

Xcode 6.4, for iOS8.4, ARC enabled

There are many posts on this topic. It seemed to me that this is not a clear solution, so I spent several hours of testing and finally put together a solution that helps solve the OP problem:

"I'm trying to dismiss the UIAlertView before showing to others ..."

As stated in the OP, the ".windows" method will no longer work. There are some other ways that I read about this, including creating a category for UIAlertView and others using notifications; however they were too complicated for me.

Here's what to do ...

1) Match your class with UIAlertViewDelegate.

In your "* .h" file of your class ...

 @interface YourViewController : UIViewController <UIAlertViewDelegate> 

This will allow the UIAlertView object in your class to send messages to the following method:

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

and for the UIAlertView object in your class to receive messages using the following method:

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

A word wise, you do not have to, in some situations your class is compatible with UIAlertViewDelegate, but it is a safer choice. It all depends on how you use your object in your class.

2) Declare the UIAlertView objet as a class variable or as a property.

Some of the advantages of creating a property are that you can have access to certain getters and setters of the object.

As an instance variable in your "* .h" file of your class ...

 @interface YourViewController : UIViewController <UIAlertViewDelegate> { UIAlertView *yourAlertView; { //other properties @end 

As a property (recommended) in your "* .h" file of your class ...

 @interface YourViewController : UIViewController <UIAlertViewDelegate> { //other instance variables { @property (strong, nonatomic) UIAlertView *yourAlertView; @end 

3) Avoid creating multiple links to your UIAlertView object.

For example, if you have a method that monitors a specific condition and displays a warning, then do not create a UIAlertView object each time. Instead, create it once in -(void)viewDidLoad and use it where you need it. Otherwise, it will prevent

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

from sending the desired message to the correct UIAlertView object.

4) Assign the tag to the UIAlertView object and process the properties to change the title, message, etc.

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

5) Show the UIAlertView object.

 [self.yourAlertView show]; 

6) Reject until the modified UIAlertView object is displayed.

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

7) UIAlertView depreciates in iOS8.

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 alerts and manage them in iOS 8 and later, use the UIAlertController with preferredStyle UIAlertControllerStyleAlert instead.

In applications running on versions of iOS prior to iOS 8, use the UIAlertView Class to display a warning message to the user. Warning to view functions similar, but different in appearance from the action sheet (an instance of the UIActionSheet).

Use the properties and methods defined in this class to set the title, message, and delegate from the alert view and customize the buttons. You must have a delegate installed if you add custom buttons. The delegate must conform to the UIAlertViewDelegate protocol. Use the show method to display a warning view after you configure it.

+1
source share

I had the same problem and did not want to keep all possible kinds of warnings 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 a comment on one of the posts, there is an explanation why the old approach does not work in iOS 7:

In iOS7, windows do not contain an alert preview window. They are controlled by another stack of windows that are not displayed.

Hope this helps someone else. :)

0
source share

Code to reject all warnings. This is a PRIVATE API, so your application may be rejected by Apple when loading into the Appstore:

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

All Articles