Zev Eisenbergの答えは単純明快ですが、常に機能するとは限らず、次の警告メッセージで失敗することがあります。
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
これは、ウィンドウのrootViewControllerが表示されたビューの上部にないためです。これを修正するには、Swift 3で作成したUIAlertController拡張コードに示されているように、プレゼンテーションチェーンを上に移動する必要があります。
/// 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)
}
2017年9月15日の更新:
上記のロジックが新しく利用可能なiOS 11 GMシードで引き続き適切に機能することをテストして確認しました。ただし、アジリティビジョンで上位に投票されたメソッドはそうではありません。新しく作成されたアラートに表示されるアラートビューUIWindow
はキーボードの下にあり、ユーザーがボタンをタップできない可能性があります。これは、iOS 11では、キーボードウィンドウよりも高いすべてのwindowLevelsがその下のレベルに引き下げられるためです。
keyWindow
ただし、警告が表示されるとキーボードが下にスライドし、警告が解除されるとキーボードが再び上にスライドするアニメーションが1つあります。プレゼンテーション中にキーボードをそのままにしたい場合は、以下のコードに示すように、トップウィンドウ自体からプレゼンテーションを試すことができます。
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シードで適切に機能し、適切な色合いで、キーボードのスライドアーティファクトがありません。