Odpowiedź Zeva Eisenberga jest prosta i jednoznaczna, ale nie zawsze działa i może nie powieść się z tym komunikatem ostrzegawczym:
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
Wynika to z faktu, że rootViewController systemu Windows nie znajduje się na górze prezentowanych widoków. Aby to naprawić, musimy przejść do łańcucha prezentacji, jak pokazano w moim kodzie rozszerzenia UIAlertController napisanym w Swift 3:
/// show the alert in a view controller if specified; otherwise show from window's root pree
func show(inViewController: UIViewController?) {
if let vc = inViewController {
vc.present(self, animated: true, completion: nil)
} else {
// find the root, then walk up the chain
var viewController = UIApplication.shared.keyWindow?.rootViewController
var presentedVC = viewController?.presentedViewController
while presentedVC != nil {
viewController = presentedVC
presentedVC = viewController?.presentedViewController
}
// now we present
viewController?.present(self, animated: true, completion: nil)
}
}
func show() {
show(inViewController: nil)
}
Aktualizacje 15.09.2017:
Przetestowano i potwierdzono, że powyższa logika nadal działa świetnie w nowo dostępnym ziarnie iOS 11 GM. Metoda najczęściej wybierana przez agilityvision nie: jednak widok alertu przedstawiony w nowej wersji UIWindow
znajduje się pod klawiaturą i potencjalnie uniemożliwia użytkownikowi dotykanie przycisków. Wynika to z faktu, że w iOS 11 wszystkie poziomy okna wyższe niż okna klawiatury są obniżone do poziomu poniżej.
Jednym z artefaktów prezentacji keyWindow
jest jednak animacja zsuwania się klawiatury po wyświetleniu alertu i przesuwania się ponownie po odrzuceniu alertu. Jeśli chcesz, aby klawiatura pozostała tam podczas prezentacji, możesz spróbować przedstawić ją z poziomu samego górnego okna, jak pokazano w poniższym kodzie:
func show(inViewController: UIViewController?) {
if let vc = inViewController {
vc.present(self, animated: true, completion: nil)
} else {
// get a "solid" window with the highest level
let alertWindow = UIApplication.shared.windows.filter { $0.tintColor != nil || $0.className() == "UIRemoteKeyboardWindow" }.sorted(by: { (w1, w2) -> Bool in
return w1.windowLevel < w2.windowLevel
}).last
// save the top window's tint color
let savedTintColor = alertWindow?.tintColor
alertWindow?.tintColor = UIApplication.shared.keyWindow?.tintColor
// walk up the presentation tree
var viewController = alertWindow?.rootViewController
while viewController?.presentedViewController != nil {
viewController = viewController?.presentedViewController
}
viewController?.present(self, animated: true, completion: nil)
// restore the top window's tint color
if let tintColor = savedTintColor {
alertWindow?.tintColor = tintColor
}
}
}
Jedyną niezbyt dużą częścią powyższego kodu jest to, że sprawdza nazwę klasy, UIRemoteKeyboardWindow
aby upewnić się, że możemy ją również dołączyć. Niemniej jednak powyższy kod działa świetnie w ziarnach iOS 9, 10 i 11 GM, z odpowiednim kolorem odcienia i bez przesuwanych artefaktów klawiatury.