我有 working iOS application
为了 support iOS8
,我正在替换 UIAlertView/UIActionSheet with
UIAlertController
。
问题:
为了显示UIAlertController我需要presentViewController
UIViewController类的方法。
但是 UIAlertView是从 inherited
的类中显示的
UIView or NSObject
,
由于显而易见的原因,我无法获得[self presentViewController...]
方法。
我的工作:
我尝试使用rootViewController表单当前窗口并显示UIAlertController。
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]
但是有一些旋转问题,比如我的当前视图控制器没有旋转支持 如果UIAlertController打开,它将旋转。
问题:
有没有人遇到同样的问题,并有安全的解决方案?
如果是,请提供一些示例或给出一些指导
答案 0 :(得分:42)
我今天解决了一个本质上类似的问题。就像Jageen一样,我遇到了一个我希望呈现UIAlertController但来自非UIViewController类的情况。就我而言,我希望在运行HTTP请求的故障块时弹出警报。
这就是我使用的,与我们的朋友不同,它对我来说非常完美。
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
答案 1 :(得分:14)
UIView
类的更好解决方案在
<强>的ObjectiveC 强>
UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController.........
- (UIViewController *)currentTopViewController
{
UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
while (topVC.presentedViewController)
{
topVC = topVC.presentedViewController;
}
return topVC;
}
<强>夫特强>
var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
答案 2 :(得分:11)
我的解决方案如下:
<强>夫特强>
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)
}
}
以下是示例用法:
let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
答案 3 :(得分:9)
看起来您当前(在iOS8之前)从视图对象中触发警报视图。这是非常糟糕的做法,因为一般警报应该从动作和逻辑中触发。并且该代码应该存在于控制器中。
我建议您重构当前代码,将触发警报的逻辑移动到正确的控制器,然后使用self
作为控制器轻松升级到iOS 8。
如果您从外部对象调用警报,则将控制器传递给调用警报的方法。在上游的某个地方,您必须了解控制器。
答案 4 :(得分:3)
我遇到的情况是子视图包含一个关闭它的按钮。我提出警报以确认行动。它向委托发送消息 - 包含子视图的视图控制器 - 以删除子视图
最初我从UIView呈现了一个UIAlertView。重构UIAlertController,因为UIAlertController不能像UIAlertView那样呈现自己,我想出了以下内容(在Swift中;很容易翻译成ObjC):
将协议添加到子视图中:
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)
}
为子视图添加委托,并为按钮/手势点击添加处理程序:
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)
}
}
将调用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()
...
}
...
}
这样就无需找到最顶层的视图控制器,也无需将视图控制器的引用传递给子视图(除了在对象/委托关系中)。
答案 5 :(得分:2)
在Swift 3中:
UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
答案 6 :(得分:2)
对于 Swift 4 及更高版本
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
答案 7 :(得分:0)
对于NSObject类中的显示UIAlertController,请使用Code。
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];
//将下面的方法放在全球助手类中。
- (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];
}
答案 8 :(得分:0)
通常,应在视图控制器中处理警报。以下是所需代码的示例:
Swift 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)
}
答案 9 :(得分:0)
我知道问题已经得到解决...但是由于我也在寻找相同的问题,但是上述解决方案都不适合我。
因此,在经过多次尝试和错误之后,我找到了一个非常简单且可持续的解决方案。
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
}