Swift:“尝试呈现其视图不在窗口层次结构中的UIAlertController!" [英] Swift: "Attempt to present UIAlertController whose view is not in the window hierarchy!"

查看:74
本文介绍了Swift:“尝试呈现其视图不在窗口层次结构中的UIAlertController!"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在单击按钮时显示UIAlertController(按钮单击会运行某些代码,并取决于上述结果-出现警报).最初的ViewController是默认的,我创建了第二个(ConsoleViewController).用户登录,并在成功登录后选择到下一个视图(ConsoleViewController),该视图显示数据(位于ConsoleViewController的viewDidLoad()部分中).用户单击签到"后,应用程序将捕获设备的GPS位置,当前日期/时间,并打开相机拍摄(自拍)图片.在相机中选择使用照片"(尚未对此功能进行编码)后,它将所有3个参数发送到API处理程序.

I'm trying to display a UIAlertController when a button is clicked (button click runs certain code, and depending on said outcome - the Alert shows up). The initial ViewController is the default one, and I've created a second one (ConsoleViewController). The user logs in, and upon successful log in, segues to the next view (ConsoleViewController), which displays data (which is in the viewDidLoad() section of the ConsoleViewController). Once the user clicks "Check In", the app captures the GPS location of the device, the current date/time, and opens the camera to take a (selfie) picture. Upon selection of "Use Photo" in the camera (havent coded that feature yet), it sends all 3 parameters to an API handler.

第二个按钮打开日期选择器,用户选择日期和时间.轻按提交"按钮后,label.text将使用选定的日期(从日期选择器中)更新,并弹出一个警报,指出基于API处理程序中的returnString成功保存了日期.

The second button opens a date picker and the user selects a date and time. Upon tapping the "Submit" button, a label.text is updated with the selected date (from the date picker), and an Alert should pop up stating the date was successfully saved based on the returnString from the API handler.

我遇到的问题是,我希望显示一个警报弹出窗口,显示成功"或失败",具体取决于数据是否成功发送(基于API处理程序的returnString).我不断收到错误Warning: Attempt to present <UIAlertController: 0x7fd03961b0a0> on <appName.ViewController: 0x7fd039538640> whose view is not in the window hierarchy!.我尝试将警报视图添加到主线程中,尝试更改显示序列的方式(推送,模态等),以及在StackOverFlow上可以找到的几乎所有其他内容(以及搜索Google),似乎没有解决方案对我有用.我基于错误的登录凭据(在ViewController上)创建了警报,并且该弹出窗口可以正常工作.

The issue I'm having, is that I want an Alert popup to display saying either "Success" or "Failed" depending on if the data was successfully sent or not (based on the returnString of the API handler). I keep getting the error Warning: Attempt to present <UIAlertController: 0x7fd03961b0a0> on <appName.ViewController: 0x7fd039538640> whose view is not in the window hierarchy!. I have tried adding the alert view to the main thread, I've tried changing the way the segue is presented (push, modal, etc), and just about everything else I could find here on StackOverFlow (as well as searching Google), and no solution seems to work for me. I created alerts based on incorrect login credentials (on the ViewController), and that pop up works correctly.

下面是我的代码...别介意我的随机print行...它可以帮助我跟踪自己在哪里.

Below is my code... Don't mind my random print lines...it helps me keep track of where I am lol.

注意:我已经添加了相应的info.plist项,以显示来自iOS的正确弹出窗口.这些,也告诉我它们不在视图层次结构中

    func consoleAlertPopup(title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message,     preferredStyle: UIAlertControllerStyle.alert)
        UIApplication.shared.keyWindow?.rootViewController?.present(alertController,     animated: true, completion: nil)
    alertController.addAction(UIAlertAction(title: "Try Again", style:     UIAlertActionStyle.default, handler:  nil))
}

ConsoleViewController:

ConsoleViewController:

import UIKit
import CoreLocation
import MobileCoreServices

class ConsoleViewController: UIViewController, CLLocationManagerDelegate {

var alertView: UIAlertController?

// IB Outlets \\
@IBOutlet var DisplayUserName: UILabel!
@IBOutlet var LastCheckInLabel: UILabel!
@IBOutlet var NextCourtDateLabel: UILabel!
@IBOutlet weak var CourtDateButton: UIButton!

@IBOutlet weak var courtDatePicker: UIDatePicker!

//Global Variables & UI Elements
var checkInImg: UIImage!
var userNameString: String!
var newDisplayDate: String?
var updatedCourtLabel: String?
let formatter = DateFormatter()
let displayFormatter = DateFormatter()
var locationManager: CLLocationManager!

@IBAction func clickCheckIn(_ sender: UIButton) {

    sendPicture()
    //Camera Pop Up

}

@IBAction func clickCourtDate() {

    courtPickerAction(Any.self)

}

@IBAction func courtPickerAction(_ sender: Any) {


   DatePickerDialog().show("Select Next Court Date", doneButtonTitle: "Submit", cancelButtonTitle: "Cancel", datePickerMode: .dateAndTime) {
        (courtDateTime) -> Void in

    if courtDateTime == nil {
        //Do nothing
    } else {
        self.formatter.dateFormat = "yyyy-MM-dd HH:mm"
        self.newDisplayDate = self.formatter.string(from: (courtDateTime)!)


    //print("Date after format: \(courtDateTime)")
    print("Date and time: \(self.newDisplayDate) after sendDefendantData func")


    // Submit Button - Date Picker \\
    if (DatePickerDialog().doneButton != nil) {

        self.sendDefendantData()


        print("Send Defendant Data from Submit")
        print("After sendDefData: \(self.newDisplayDate)")

        self.displayFormatter.dateStyle = DateFormatter.Style.full
        self.displayFormatter.timeStyle = DateFormatter.Style.short
        self.NextCourtDateLabel.text = self.displayFormatter.string(from: courtDateTime!)

            }

        }
    }
}


override func viewDidLoad() {
    super.viewDidLoad()


    print("Console View Did Load")
    self.hideKeyboardWhenTappedAround()

    DisplayUserName.text! = userNameString
    // For location allowance from user
    // I've placed this code here (instead of in a function) so the alert
    // pop up will show and allows accessing location. "not in hierarchy"
    // elsewise.
    self.locationManager = CLLocationManager()
    self.locationManager.delegate = self
    self.locationManager.requestWhenInUseAuthorization()

    // Format Display Date & Times
    self.displayFormatter.dateStyle = DateFormatter.Style.full
    self.displayFormatter.timeStyle = DateFormatter.Style.long


    // Retrieve Defendant Data From API Handler
    getDefendantData()





    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}




func presentAlert(_ message: String) {

    self.alertView = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
    alertView?.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in })

    ViewController().present(alertView!, animated: true, completion: nil)

}


func consoleAlertPopup(title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
    UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
    alertController.addAction(UIAlertAction(title: "Try Again", style: UIAlertActionStyle.default, handler:  nil))
}

func getDefendantData() {...}
func sendDefendantData() {...}
func sendPicture() {....}

ViewController:

ViewController:

    import UIKit


// Hide Keyboard \\
extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
    }

    func dismissKeyboard() {
        view.endEditing(true)
    }
}



class ViewController: UIViewController {

    // Send User Login to Console Screen \\
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if (segue.identifier == "toConsoleScreen") {

            let secondViewController = segue.destination as! ConsoleViewController

            secondViewController.userNameString = UserNameField.text!

            print("PrepareSegue")
        }

    }

    @IBAction func UserNameEditBegan() {
        UserNameField.text = nil
    }
    @IBAction func PasswordEditBegan() {
        PasswordField.text = nil
    }

    @IBOutlet weak var UserNameField: UITextField!
    @IBOutlet weak var PasswordField: UITextField!

    func successfulLogin(Username: String) {


        print("Inside Function")

        print(Username)
        print("Inside Successful Login")

        // Show next view - Add to Main Queue\\
        OperationQueue.main.addOperation{

            //print("Before dismissal")
            // self.dismiss(animated: true, completion: nil)
            //print("After dismissal")
            self.performSegue(withIdentifier: "toConsoleScreen", sender: self)
            print("After segue")

        }
    }



    override func viewDidLoad() {
        super.viewDidLoad()

        self.hideKeyboardWhenTappedAround()



        // Do any additional setup after loading the view, typically from a nib.


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func loginButton() {

        login(Username: UserNameField.text!, Password: PasswordField.text!) { username in
            self.successfulLogin(Username: username)
    }



}



    }

推荐答案

此行:

ViewController().present(alertView!, animated: true, completion: nil)

创建一个ViewController的新实例,并在其上调用present方法.那行不通.您需要从本身显示的视图控制器中调用它.看起来代码在ConsoleViewController内部,也许您可​​以在其中使用self.

creates a new instance of ViewController and calls the present method on it. That won't work. You need to call it from a view controller that is itself presented. It looks like that code is inside ConsoleViewController, maybe you can just use self there.

这篇关于Swift:“尝试呈现其视图不在窗口层次结构中的UIAlertController!"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆