web-dev-qa-db-ja.com

すべてのUIAlertControllerは、ユーザーが応答する前に自動的に消えます-iOS 13以降

私はiOS 13を使用しているので、各UIAlertControllerは約0.5秒間表示され、ユーザーのアクションの直前にすぐに消えます。何か案が ?

アプリのさまざまな部分からUIAlertControllerを使用しているため、クラシックビューとcollectionView(セル、ヘッダーなど)の両方からポップアップできる拡張機能を使用しています。

public extension UIAlertController {
    func show() {
        let win = UIWindow(frame: UIScreen.main.bounds)
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        vc.view.tintColor = Theme.mainAccentColor
        win.rootViewController = vc
        win.windowLevel = UIWindow.Level.alert + 1
        win.makeKeyAndVisible()
        vc.present(self, animated: true, completion: nil)
    }
}

そして、これはこの拡張機能の使用例です:

fileprivate func showMissingAlert() {
        let alert = UIAlertController(title: "blablabla", message: "blablablablabla blabla", preferredStyle: UIAlertController.Style.alert)
        alert.show()
        alert.view.tintColor = Theme.mainAccentColor
        let cancelAction = UIAlertAction(title: "OK, blabla", style: .default, handler: {(alert: UIAlertAction!) in print("ok, leave")})
        alert.addAction(cancelAction)
    }

そしてさらに私のコードでは:

showMissingAlert()

IOS 13より前は、すべてのUIAlertは問題なく動作していました...私がiOS 13に移動して以来、iOS 13.1でさえ、大きな混乱に陥っていました... :(

  • これを引き起こす原因について何か考えはありますか?

  • そして、サブリミナルメッセージとしてUIAlertを使用しないようにする方法:)?

9
Creanomy

私はまったく同じ問題を抱えており、アラートが表示されているウィンドウを強い変数で保持することで修正しました。

たとえば、AppDelegateでアラートを表示するためのウィンドウを保持して、UIAlertController拡張機能で使用できます。

//In app delegate
let alertWindow: UIWindow = {
    let win = UIWindow(frame: UIScreen.main.bounds)
    win.windowLevel = UIWindow.Level.alert + 1
    return win
}()

次に、拡張機能で:

public extension UIAlertController {
    func show() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        vc.view.tintColor = Theme.mainAccentColor
        appDelegate.alertWindow.rootViewController = vc
        appDelegate.alertWindow.makeKeyAndVisible()
        vc.present(self, animated: true, completion: nil)
    }
}

また、アラートが閉じられたときにアラートウィンドウがビューから削除されていることを確認する必要があります。そうしないと、すべてのタップが(非表示の)アラートウィンドウによって処理されるため、アプリが応答しなくなり、すべての上に表示されます。これを行うには、アラート内のすべてのアクションのハンドラーに次のコードを追加します。

(UIApplication.shared.delegate as! AppDelegate).alertWindow.isHidden = true
9
pepsy

pepsyanswer に基づいています。気にしたくない場合はalertWindow.isHidden = true stuff、次のようなことができます:

class AlertHandler {
    private static let alertWindow: UIWindow = {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.windowLevel = UIWindow.Level.alert + 1
        return window
    }()

    private var alertController: UIAlertController

    init(title: String?,
         message: String?) {
        alertController = UIAlertController(title: title,
                                            message: message,
                                            preferredStyle: .alert)
    }

    func addAction(title: String?,
                   style: UIAlertAction.Style,
                   handler: ((UIAlertAction) -> Void)? = nil) {
        let action = UIAlertAction(title: title,
                                   style: style) { action in
                                    handler?(action)
                                    AlertHandler.alertWindow.isHidden = true
        }
        alertController.addAction(action)
    }

    func present() {
        AlertHandler.alertWindow.rootViewController = UIViewController()
        AlertHandler.alertWindow.makeKeyAndVisible()
        AlertHandler.alertWindow.rootViewController?.present(alertController,
                                                             animated: true,
                                                             completion: nil)
    }
}
0
Timofey Kuzmin

このソリューションも試すことができます。私の働きです。

クラスに以下のメソッドを記述します。

func presentViewController(alertController: UIAlertController, completion: (() -> Void)? = nil) {
        if var topController = UIApplication.shared.keyWindow?.rootViewController {
            while let presentedViewController = topController.presentedViewController {
                topController = presentedViewController
            }

            DispatchQueue.main.async {
                topController.present(alertController, animated: true, completion: completion)
            }
        }
    }

次に、以下のようにコードから呼び出します

let alertController = UIAlertController(title: "Discard Photo?",
                                                message: "Your photo will not be attached",
                                                preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "Keep Photo", style: .default, handler: nil))
        alertController.addAction(UIAlertAction(title: "Discard", style: .default) { (_) -> Void in
            self.PhotoStack.deletePhoto(at: index)
            self.cameraBtn.isEnabled = true
        })

        self.presentViewController(alertController: alertController)