Показать предупреждение в AppDelegate в Swift

Я пробую следующий фрагмент кода:

var alert = UIAlertController(title: "Alert", message: "Cannot connect to : \(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)

в моем AppDelegate, но он печатает мне следующую ошибку в консоли:

Warning: Attempt to present <UIAlertController: 0x7ff6cd827a30> on <Messenger.WelcomeController: 0x7ff6cb51c940> whose view is not in the window hierarchy!

Как я могу исправить эту ошибку?

Ответы

Ответ 1

Вот что я сейчас использую для этого.

var alertController = UIAlertController(title: "Title", message: "Any message", preferredStyle: .ActionSheet)
var okAction = UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default) {
                    UIAlertAction in
                    NSLog("OK Pressed")
                }
var cancelAction = UIAlertAction(title: "No", style: UIAlertActionStyle.Cancel) {
                    UIAlertAction in
                    NSLog("Cancel Pressed")
                }
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

Ответ 2

SWIFT 3

let alert = UIAlertController(title: "Test", message:"Message", preferredStyle: UIAlertControllerStyle.alert)

// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))

// show the alert
self.window?.rootViewController?.present(alert, animated: true, completion: nil)

Ответ 3

Swift 3.0 или выше, работа во всех условиях, например, в случае панели вкладок, в случае представленного представления и т.д.

let alert = UIAlertController(title: "Test", message:"Message", preferredStyle: UIAlertControllerStyle.alert)

// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))

// show alert
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)

Ответ 4

Я предполагаю, что вы вызываете этот фрагмент кода из applicationDidFinishLunchingWithOptions:. Я попробовал это на самом деле, потому что должен был. Дело в том, что то, что вы пытаетесь сделать, является правильным, но ViewController, который AppDelegate делает и представляет, собирается поставить на экран, и до этого фрагмент кода пытается создать alertView и вставить поверх существующего представления RootViewController.

Что бы я сделал, это переместить его на другой вызов делегата, который, как гарантируется, будет вызываться после представления RootViewController.

    func applicationDidBecomeActive(application: UIApplication) {
     //This method is called when the rootViewController is set and the view.
     // And the View controller is ready to get touches or events.
    var alert = UIAlertController(title: "Alert", message: "Cannot connect to :", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
    self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)

    }

Но как всегда знаю ответственность AppDelegate. Он предназначен для обработки вызовов и событий делегатов на протяжении всего жизненного цикла приложения и приложений. Если ввод кода здесь имеет смысл, тогда сделайте это. Но если вам будет лучше помещать код в rootViewController или другие части, тогда подумайте об этом.

В любом случае, надеюсь, что это поможет. Ура!

Ответ 5

Пробовали ли вы использовать UIApplication.shared.keyWindow?.rootViewController?.present(...)?

Ответ 6

У меня была аналогичная проблема.

Я исправил его, представив UIAlertController в Main Queue.

Код выглядит следующим образом.

let alert = UIAlertController(title: "My Title", message: "My Message", preferredStyle: .alert)

let actionYes = UIAlertAction(title: "Yes", style: .default, handler: { action in
print("action yes handler")
})

let actionCancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { action in
print("action cancel handler")
})

alert.addAction(actionYes)
alert.addAction(actionCancel)

DispatchQueue.main.async {
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}

Ответ 7

Как ответ Хорхе, обновленный для Swift 4

let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
        UIAlertAction in
        NSLog("OK Pressed")
    }
let cancelAction = UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.cancel) {
        UIAlertAction in
        NSLog("Cancel Pressed")
    }
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)

Ответ 8

Я бы предложил НЕ делать это в AppDelegate. Делегат приложения предназначен для обработки функций делегата из ОС, а не для реализации таких вещей, как представления предупреждений.

Если вы хотите представить представление предупреждения, которое будет показано в начале приложения, я бы сделал это, выполнив его в вашем первом контроллере представления.