UIAlertController无法显示 - 在Swift中

12
我已经创建了一个 ContactUsViewController 控制器。
在这个控制器中,用户将从 pickerView 中选择一个选项,然后在 textView 中输入消息并按下“发送电子邮件”按钮。
当他们按下按钮时,它会创建一个 MFMailComposeViewController,以便他们可以发送电子邮件。现在,当电子邮件被发送、保存、取消或失败时,MFMailComposeViewController 将关闭,因为他们回到了我的应用程序。我希望一个警报出现,告诉他们刚刚发生了什么更新。我最初使用 UIAlertView 设置了这个,并将此代码放置在 fun mailComposeController 函数中,请参见下面的代码:
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {

    switch result.rawValue {

    case MFMailComposeResultCancelled.rawValue:
        NSLog("Email cancelled")
    case MFMailComposeResultSaved.rawValue:
        NSLog("Email saved")
        let sendMailErrorAlert = UIAlertView(title: "Email saved", message: "Your email has been saved in Mail.", delegate: self, cancelButtonTitle: "OK")
        sendMailErrorAlert.show()
    case MFMailComposeResultSent.rawValue:
        NSLog("Email sent")

        let alertController = UIAlertController(title: "test", message: "test", preferredStyle: .Alert)
        let okButton = UIAlertAction(title: "Okay", style: .Default, handler: nil)
        alertController.addAction(okButton)
        presentViewController(alertController, animated: true, completion: nil)

    case MFMailComposeResultFailed.rawValue:
        NSLog("Email failed: %@", [error!.localizedDescription])
        let sendMailErrorAlert = UIAlertView(title: "Oops!", message: "Looks like something went wrong, and the email couldn't send. Please try again later.", delegate: self, cancelButtonTitle: "OK")
        sendMailErrorAlert.show()
    default:
        break

    }

如您所见,我使用了UIAlertView来处理“电子邮件已保存”和“电子邮件发送失败”的情况。这个方法非常好用,能够按预期显示提示信息。 最近我看到iOS 8以后UIAlertView被弃用了,现在我们应该使用UIAlertController。因此,我尝试使用UIAlertController来创建同样的提示框,您可以在“电子邮件已发送”部分看到。然而,它似乎不起作用,没有显示任何提示信息。日志中会打印出以下错误信息:
Warning: Attempt to present <UIAlertController: 0x126c50d30> on <XXXX.ContactUsViewController: 0x1269cda70> whose view is not in the window hierarchy! 

但我并不确定这是什么意思,更重要的是,如何解决它。

我的问题是:

  1. 我说不能使用UIAlertView,这样说对吗?
  2. 我该如何修复它并使UIAlerController在从邮件应用程序返回后出现?

提前感谢。

4个回答

12
问题在于当你调用以下函数时已经晚了:
present(alertController, animated: true, completion: nil)

您的邮件视图控制器仍然可见。您必须确保alertController在窗口层次结构的顶部呈现。在您的示例中,您有以下窗口层次结构:

+---------------------------+
| MailComposeViewController |
+---------------------------+
            ||
+---------------------------+
|  ContactUsViewController  |
+---------------------------+

相反,您应该先关闭电子邮件视图控制器,然后再显示警报视图控制器。

let alertController = UIAlertController(title: "test", message: "test", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "Okay", style: .Default, handler: nil)
alertController.addAction(okButton)
controller.dismissViewControllerAnimated(true){ () -> Void in
     self.present(alertController, animated: true, completion: nil)   
}

或者,您也可以将alertController显示在MailComposeViewController的顶部,像这样:

let alertController = UIAlertController(title: "test", message: "test", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "Okay", style: .Default, handler: nil)
alertController.addAction(okButton)
controller.present(alertController, animated: true, completion: nil)

4

在使用DispachQueue.main.async{}后,我现在已经解决了同样的问题,代码可以正常工作。


3

我需要的是一个操作表(actionSheet),而不是警告(alert),基于我的特殊情况,这里提供的解决方案都无法满足我的需求。如果你的UIAlertController没有显示出来,另一种替代方法是将其始终放在最顶层窗口(Swift 4 中):

func topmostController() -> UIViewController? {
    if var topController = UIApplication.shared.keyWindow?.rootViewController {
        while let presentedViewController = topController.presentedViewController {
            topController = presentedViewController
        }
        return topController
    }
    return nil
}

// Now put up the menu
let menu=UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
menu.addAction(UIAlertAction(title: "Test", style: .default, handler: {_ in self.doTest()} ))
menu.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {_ in self.doCancel()} ))
topmostController()?.present(menu, animated: true, completion: nil)
无论您的视图控制器堆栈如何,都会显示此窗口。

这个解决方案在我的情况下起作用了,我有两个视图控制器和一个UI视图在其上面。谢谢。 - Marcin Żmigrodzki

-1

Swift 4

不再显示警告消息

在DidLoad中

let AlertOnce = UserDefaults.standard
    if(!AlertOnce.bool(forKey: "oneTimeAlert")){


        let messageTitle = "Your selected branch is \(storeIDName)"
        let alertView = UIAlertController(title: messageTitle, message: "", preferredStyle: .actionSheet)
        let DoNotShowAgainAction = UIAlertAction(title: "Do Not Show Again", style: UIAlertActionStyle.default) { (action:UIAlertAction) in

            AlertOnce.set(true , forKey: "oneTimeAlert")
            AlertOnce.synchronize()

        }
        let change = UIAlertAction(title: "Change Branch", style: .default){(action) in
            let myVC = self.storyboard?.instantiateViewController(withIdentifier: "FindRestaurentViewControllerID") as! FindRestaurentViewController
            self.navigationController?.pushViewController(myVC, animated: true)
        }
        alertView.addAction(DoNotShowAgainAction)
        alertView.addAction(change)
        present(alertView, animated: true,completion: nil)
        alertView.setValue(NSAttributedString(string: messageTitle, attributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 20),NSAttributedStringKey.foregroundColor : UIColor(red: 234/256, green: 104/256, blue: 26/256, alpha: 1)]), forKey: "attributedTitle")
        alertView.view.tintColor = UIColor.black

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接