Display UIAlertController from UIView/NSObject cla

2019-01-14 06:27发布

I have working iOS application In order to support iOS8, I am replacing UIAlertView/UIActionSheet with UIAlertController.

Problem :
For display UIAlertController I need presentViewController method of UIViewController class.
But UIAlertView is display from classes which are inherited from UIView or NSObject,
I can not get [self presentViewController...] method for obvious reason.

My Work :
I tried getting rootViewController form current window and display UIAlertController.

[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]

but have some rotation problems like if my current view controller do not have rotation support it will rotate if UIAlertController is open.

Question :
Did any one faced same problem and have safe solution ?
if yes please provide me some example or give some guide

10条回答
我想做一个坏孩纸
2楼-- · 2019-01-14 07:05

I have had this problem. See my SO answer here for the code to get the topmost view controller with which to present another view controller.

I agree that for most cases it is bad practice to present a view controller from an object that is not a view controller, but sometimes you DO need to.

查看更多
男人必须洒脱
3楼-- · 2019-01-14 07:07

It looks like you are currently (pre-iOS8) triggering an alert view from within your view object. That's pretty bad practice, as in general alerts should be triggered from actions and logic. And that code should live in controllers.

I suggest you refactor your current code to move the logic that triggers the alert to the correct controller, and then you can easily upgrade to iOS 8 by using self as the controller.

If instead you're calling the alert from an outside object, then pass in the controller to the method that calls the alert. Somewhere upstream you must have knowledge of the controller.

查看更多
Lonely孤独者°
4楼-- · 2019-01-14 07:07

My solution is below:

Swift

class alert {
    func msg(message: String, title: String = "")
    {
        let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert)

        alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil))

        UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil)
    }
}

Here is sample usage:

let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
查看更多
ら.Afraid
5楼-- · 2019-01-14 07:13

The better solution for UIView classes is below

ObjectiveC

UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController......... 

- (UIViewController *)currentTopViewController
{
    UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (topVC.presentedViewController)
    {
        topVC = topVC.presentedViewController;
    }
    return topVC;
}

Swift

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
查看更多
爷的心禁止访问
6楼-- · 2019-01-14 07:23

For Swift 4 and above

UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
查看更多
一夜七次
7楼-- · 2019-01-14 07:24

I solved an essentially similar problem today. Like Jageen, I ran into a situation where I wanted to present a UIAlertController but from a non-UIViewController class. In my case, I wanted an alert to pop up when the failure block of a HTTP request is run.

This is what I used and unlike our friend here, it worked quite perfectly for me.

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
查看更多
登录 后发表回答