I have a tableview which, when loaded, each cell could possibly return an NSError, which I have chosen to display in a UIAlertController. Problem is I get this error in the
For latest Swift language you can use following:
var alert = presentedViewController
if alert != nil && (alert is UIAlertController) {
// YES UIAlertController is already presented*
} else {
// UIAlertController is not presented OR visible.
}
if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {
// UIAlertController is presenting.Here
}
I found I needed to create a queue to stack the UIAlertController requests.
NSMutableArray *errorMessagesToShow; // in @interface
errorMessagesToShow=[[NSMutableArray alloc] init]; // in init
-(void)showError:(NSString *)theErrorMessage{
if(theErrorMessage.length>0){
[errorMessagesToShow addObject:theErrorMessage];
[self showError1];
}
}
-(void)showError1{
NSString *theErrorMessage;
if([errorMessagesToShow count]==0)return; // queue finished
UIViewController* parentController =[[UIApplication sharedApplication]keyWindow].rootViewController;
while( parentController.presentedViewController &&
parentController != parentController.presentedViewController ){
parentController = parentController.presentedViewController;
}
if([parentController isKindOfClass:[UIAlertController class]])return; // busy
// construct the alert using [errorMessagesToShow objectAtIndex:0]
// add to each UIAlertAction completionHandler [self showError1];
// then
[errorMessagesToShow removeObjectAtIndex:0];
[parentController presentViewController:alert animated:YES completion:nil];
}
Swift 4.2+ Answer
if UIApplication.topViewController()!.isKind(of: UIAlertController.self) {
print("UIAlertController is presented")}
For those who don't know how to get top most Viewcontroller
extension UIApplication {
public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(presented)
}
return base
}}
Swift 5+ Answer 'keyWindow' was deprecated in iOS 13.0 suggested edit
if UIApplication.topViewController()!.isKind(of: UIAlertController.self) {
print("UIAlertController is presented")}
For those who don't know how to get top most Viewcontroller
extension UIApplication {
public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(presented)
}
return base
}}
It is not the UIAlertController that is "already presenting", it is MessagesMasterVC. A view controller can only present one other view controller at a time. Hence the error message.
In other words, if you have told a view controller to presentViewController:...
, you cannot do that again until the presented view controller has been dismissed.
You can ask the MessagesMasterVC whether it is already presenting a view controller by examining its presentedViewController
. If not nil
, do not tell it to presentViewController:...
- it is already presenting a view controller.
I used that to detect and remove and alert.
First we create an alert with following function.
var yourAlert :UIAlertController!
func useYouAlert (header: String, info:String){
yourAlert = UIAlertController(title:header as String, message: info as String, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: self.langText[62]as String, style: UIAlertActionStyle.default) { (result : UIAlertAction) -> Void in
print("OK")
}
yourAlert.addAction(okAction)
self.present(yourAlert.addAction, animated: true, completion: nil)
}
And in some other part of your code
if yourAlert != nil {
yourAlert.dismiss(animated: true, completion: nil)
}