objective-c 从 UIView/NSObject 类显示 UIAlertController
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25505045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Display UIAlertController from UIView/NSObject class
提问by Jageen
I have working iOS applicationIn order to support iOS8, I am replacing UIAlertView/UIActionSheet with
UIAlertController.
我有working iOS application为了support iOS8,我正在更换UIAlertView/UIActionSheet with
UIAlertController。
Problem :
For display UIAlertController I need presentViewController
method of UIViewController class.
ButUIAlertView is display from classes which are inheritedfrom
UIView or NSObject,
I can not get [self presentViewController...]method for obvious reason.
问题:
为了显示 UIAlertController,我需要 UIViewController 类的 presentViewController 方法。
但是UIAlertView中是从哪个是类显示器inherited的
UIView or NSObject,
我不能[self presentViewController...]为明显的原因的方法。
My Work :
I tried getting rootViewController form current window and display UIAlertController.
我的工作:
我尝试从当前窗口获取 rootViewController 并显示 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.
但是有一些旋转问题,比如如果我当前的视图控制器没有旋转支持,它会在 UIAlertController 打开时旋转。
Question :
Did any one faced same problem and have safe solution ?
if yes please provide me some example or give some guide
问题:
有没有人遇到过同样的问题并有安全的解决方案?
如果是,请给我一些例子或给一些指导
采纳答案by Rikkles
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.
看起来您当前(iOS8 之前)正在从您的视图对象中触发警报视图。这是非常糟糕的做法,因为通常警报应该从操作和逻辑中触发。并且该代码应该存在于控制器中。
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 selfas the controller.
我建议您重构您当前的代码,将触发警报的逻辑移动到正确的控制器,然后您可以通过self用作控制器轻松升级到 iOS 8 。
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.
相反,如果您从外部对象调用警报,则将控制器传递给调用警报的方法。在上游的某个地方,您必须了解控制器。
回答by Lester
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.
我今天解决了一个本质上类似的问题。像Jageen一样,我遇到了一种情况,我想呈现一个 UIAlertController 但来自非 UIViewController 类。就我而言,我希望在运行 HTTP 请求的失败块时弹出警报。
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)
回答by Shamsudheen TK
The better solution for UIViewclasses is below
更好的UIView类解决方案如下
ObjectiveC
目标C
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........
回答by fattihkoca
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!")
回答by Adrian Mannella
I had a situation where a subview contains a button to dismiss it. I present an alert to confirm the action. It sends a message to the delegate - which is the view controller containing the subview - to remove the subview
我遇到过一个子视图包含一个关闭它的按钮的情况。我发出警报以确认该操作。它向委托发送消息 - 这是包含子视图的视图控制器 - 以删除子视图
Originally I presented a UIAlertView from a UIView. Refactoring for UIAlertController, since the UIAlertController can't present itself like a UIAlertView can, I came up with the following (in Swift; easily translated to ObjC):
最初我从 UIView 呈现了一个 UIAlertView。重构 UIAlertController,因为 UIAlertController 不能像 UIAlertView 那样呈现自己,我想出了以下内容(在 Swift 中;很容易转换为 ObjC):
Add a protocol to the subview:
在子视图中添加协议:
protocol MySubviewDelegate {
// called when user taps subview/delete button
// or, you could call it from a gesture handler, etc.
func displayAlert(alert : UIAlertController)
// called when user confirms delete from the alert controller
func shouldRemoveSubview(sender : AnyObject)
}
Add a delegate for the subview, and add a handler for the button/gesture tap:
为子视图添加一个委托,并为按钮/手势点击添加一个处理程序:
class MySubview : UIView {
var subviewDelegate : MySubviewDelegate!
...
func handleTap(sender : AnyObject) {
// set up the alert controller here
var alert = UIAlertController(title: "Confirm Delete",
message: "This action is permanent. Do you wish to continue?",
preferredStyle: UIAlertControllerStyle.Alert)
// Cancel action
// nil handler means "no action if Cancel button selected"
alert.addAction(UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.Cancel,
handler: nil))
// Confirm action
alert.addAction(UIAlertAction(title: "Confirm",
style: UIAlertActionStyle.Default,
handler: { (action : UIAlertAction!) -> Void in
// call delegate method to perform confirmed action, - i.e. remove
self.subviewDelegate.shouldRemoveSubview(self)
}))
// call delegate method to display alert controller
// send alert object to delegate
self.subviewDelegate.displayAlert(alert)
}
}
Set the calling UIViewController as the delegate of the subview, e.g., in its viewDidLoad() method, and include protocol methods:
将调用 UIViewController 设置为子视图的委托,例如,在其 viewDidLoad() 方法中,并包含协议方法:
class viewController : UIViewController, MySubviewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.subviewDelegate = self
...
}
func displayAlert(alert : UIAlertController) {
presentViewController(alert, animated: true, completion: nil)
}
func shouldRemoveSubview(sender : AnyObject) {
// cast as UIView / MySubview subclass
var subview = sender as MySubview
// remove the subview / perform the desired action
subview.removeFromSuperview()
...
}
...
}
This avoids the need to find the topmost view controller, or pass references to view controllers to subviews (other than in an object/delegate relationship).
这避免了需要找到最顶层的视图控制器,或将视图控制器的引用传递给子视图(对象/委托关系除外)。
回答by raed
For Swift 4and above
对于Swift 4及更高版本
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
回答by Md. Najmul Hasan
In Swift 3:
在 Swift 3 中:
UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
回答by Parth Patel
For Display UIAlertController in NSObject Class use below Code.
对于在 NSObject 类中显示 UIAlertController 使用下面的代码。
UIAlertController * popup = [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
[popup dismissViewControllerAnimated:YES completion:nil];
}];
[popup addAction:cancel];
UIViewController *rootViewController = [[Helper shareInstance] topViewController];
[rootViewController presentViewController:popup animated:YES completion:nil];
// Put Below Method in Your Global Helper Class.
// 将下面的方法放在您的全局助手类中。
- (UIViewController *)topViewController {
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewController:(UIViewController *)rootViewController {
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
回答by curest0x1021
In general, alerts should be handled in the view controller. Here's an example of the code required:
一般来说,警报应该在视图控制器中处理。以下是所需代码的示例:
Swift 3
斯威夫特 3
private func displayError(message: String) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
alertController.addAction(okayAction)
present(alertController, animated: true, completion: nil)
}
回答by Meet Patel
I know the question has been already answered... But As I am also looking for the same issue, but none of the above solutions worked for me.
我知道这个问题已经得到了回答......但是因为我也在寻找同样的问题,但上述解决方案都不适合我。
So after doing many try and error finally, I found a very easy and sustainable solution.
因此,经过多次尝试和错误最终,我找到了一个非常简单且可持续的解决方案。
func showError(title: String?, error: String?) {
DispatchQueue.main.async(execute: {
let alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
CommonMethods.instance.topMostController()?.present(alert, animated: true, completion: nil)
})
}
static let instance = CommonMethods()
fileprivate func topMostController() -> UIViewController? {
var presentedVC = UIApplication.shared.keyWindow?.rootViewController
while let pVC = presentedVC?.presentedViewController {
presentedVC = pVC
}
if presentedVC == nil { }
return presentedVC
}

