Swift: Опит за представяне на UIAlertController, чийто изглед не е в йерархията на прозореца!

Опитвам се да покажа UIAlertController, когато се щракне върху бутон (щракването върху бутон изпълнява определен код и в зависимост от посочения резултат - предупреждението се показва). Първоначалният ViewController е този по подразбиране и аз създадох втори (ConsoleViewController). Потребителят влиза и при успешно влизане преминава към следващия изглед (ConsoleViewController), който показва данни (които са в секцията viewDidLoad() на ConsoleViewController). След като потребителят щракне върху „Регистриране“, приложението улавя GPS местоположението на устройството, текущата дата/час и отваря камерата, за да направи (селфи) снимка. При избор на „Използване на снимка“ в камерата (все още не е кодирана тази функция), тя изпраща всичките 3 параметъра на манипулатор на API.

Вторият бутон отваря инструмент за избор на дата и потребителят избира дата и час. При докосване на бутона „Изпращане“, label.text се актуализира с избраната дата (от инструмента за избор на дата) и трябва да се появи предупреждение, посочващо, че датата е била успешно запазена въз основа на returnString от манипулатора на API.

Проблемът, който имам, е, че искам да се покаже изскачащ прозорец за предупреждение, който казва или „Успех“, или „Неуспешно“ в зависимост от това дали данните са изпратени успешно или не (въз основа на returnString на манипулатора на API). Продължавам да получавам грешката Warning: Attempt to present <UIAlertController: 0x7fd03961b0a0> on <appName.ViewController: 0x7fd039538640> whose view is not in the window hierarchy!. Опитах се да добавя изгледа за предупреждение към основната нишка, опитах се да променя начина, по който се представя сегментът (push, модален и т.н.) и почти всичко останало, което можах да намеря тук в StackOverFlow (както и при търсене в Google), и никакво решение изглежда не работи за мен. Създадох предупреждения въз основа на неправилни идентификационни данни за вход (на ViewController) и този изскачащ прозорец работи правилно.

По-долу е моят код... Не обръщайте внимание на произволните ми print реда... той ми помага да следя къде се намирам хаха.

Забележка: Добавих съответните елементи 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:

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:

    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)
    }



}



    }

person szady    schedule 06.03.2017    source източник
comment
Прегледахте ли внимателно тези резултати от търсенето?   -  person rmaddy    schedule 07.03.2017
comment
Уверете се, че сте задали modalPresentationStyle = .overCurrentContext на вашия UIAlertViewController.   -  person onnoweb    schedule 07.03.2017
comment
Можете ли да почистите кода си, като 1) премахнете ненужните интервали 2) коментирате реда, който показва грешката 3) запазите въпроса възможно най-кратък? Така че хората да имат време да го прочетат?   -  person Bright Future    schedule 07.03.2017
comment
Защо трябва да представите предупреждението в ViewController, а не само в self?   -  person chengsam    schedule 07.03.2017


Отговори (2)


Този ред:

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

създава нов екземпляр на ViewController и извиква метода present върху него. Това няма да работи. Трябва да го извикате от контролер за изглед, който е представен. Изглежда, че този код е вътре в ConsoleViewController, може би можете просто да използвате self там.

person Dave Weston    schedule 07.03.2017
comment
Благодаря ти! Всъщност съм доста ядосан на себе си, че не го разбрах... Моля, игнорирайте невежеството ми... - person szady; 08.03.2017
comment
Моля! И не се тревожи за това. Всички сме били там. - person Dave Weston; 08.03.2017
comment
Едно последно нещо... Известието на iOS за разрешаване на използването на GPS/камера, което бих искал да се показва, след като потребителят щракне върху бутон. Поставих self.locationManager.requestWhenInUseAuthorization() в IB действието за щракване върху бутона, но пише "Warning: Attempt to present <app name: 0x100f4c410> on <app name.ConsoleViewController: 0x100f43e40> while a presentation is in progress! Някаква представа? - person szady; 08.03.2017
comment
Изглежда, че има два различни контролера за изглед, представени едновременно. Може да искате да преместите това повикване към requestWhenInUseAuthorization към метод на по-късен жизнен цикъл, като viewDidAppear. - person Dave Weston; 08.03.2017

Не. Опитвам се да направя заявката, използвайки JOOQ renerated рутинни процедури. Сега генерираният е идентичен с този, който получавам, когато функцията връща само един запис. Не мога да получа резултат, описан тук jooq.org/doc/3.5/manual/sql-building/table-expressions/
person HIEPING    schedule 16.07.2017