Зев Айзенберг ответ прост и прямолинеен, но он не всегда работает, и он может потерпеть неудачу с этим предупреждением:
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
Это связано с тем, что rootViewController для Windows находится не в верхней части представленных представлений. Чтобы исправить это, нам нужно пройтись по цепочке презентаций, как показано в моем коде расширения UIAlertController, написанном в 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)
}
Обновления от 15.09.2017:
Протестировано и подтверждено, что вышеуказанная логика все еще отлично работает в недавно появившемся семени iOS 11 GM. Однако метод agilityvision, получивший наибольшее количество голосов, не делает этого: представление предупреждений, представленное недавно отчеканенным, UIWindow
находится под клавиатурой и потенциально не позволяет пользователю нажимать на его кнопки. Это связано с тем, что в iOS 11 все уровни окна выше, чем у окна клавиатуры, опускаются до уровня ниже него.
Одним из артефактов представления из-за этого keyWindow
является анимация, когда клавиатура скользит вниз при появлении предупреждения и снова сдвигается вверх при отклонении предупреждения. Если вы хотите, чтобы клавиатура оставалась там во время презентации, вы можете попытаться представить ее из самого верхнего окна, как показано в приведенном ниже коде:
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
}
}
}
Единственная не столь значительная часть приведенного выше кода состоит в том, что он проверяет имя класса, UIRemoteKeyboardWindow
чтобы убедиться, что мы тоже можем его включить. Тем не менее приведенный выше код отлично работает в iOS 9, 10 и 11 GM seed, с правильным оттенком цвета и без артефактов скольжения клавиатуры.