LoginSignup
24
24

More than 5 years have passed since last update.

多重呼び出しに対応したUIAlertController

Last updated at Posted at 2015-08-19

iOS8からUIAlertViewはDeplecatedになり、UIAlertControllerが登場しました。
しかし、UIAlertControllerは既にひとつ表示されているとそのアラートを消さない限り次のアラートは表示できません。
UIAlertViewのように表示中に次のアラートを呼び出せるものが必要だったので簡易的なものですが作ってみました。

公開から時間が経ったので更新しました。
AlertControllerからQUAlertControllerにリネームしております。

特徴

  • Swift3.2
  • ボタンが選択される度にshow()で呼び出した順に表示

クラス定義

QUAlertController.swift
/// 多重呼び出しに対応したUIAlertController. 登録した順に表示します
open class QUAlertController: UIAlertController {

    fileprivate static var queue = [QUAlertController]()

    /// キューにAlertControllerを追加
    ///
    /// - Parameter alert: QUAlertController
    fileprivate class func addQueue(_ alert: QUAlertController) {
        QUAlertController.queue.insert(alert, at: 0)
    }

    /// キューからAlertControllerを削除
    fileprivate class func removeQueue() {
        QUAlertController.queue.removeLast()
    }

    /// キューから全て削除
    class func removeAllQueue() {
        QUAlertController.queue.removeAll()
    }

    /// 次に表示すべきQUAlertController
    fileprivate class var nextAlertController: QUAlertController? {
        // 末尾を返す
        return queue.last
    }

    /// QUAlertControllerを表示します。既に表示中の場合は表示しません。
    fileprivate class func showAlert() {
        DispatchQueue.main.async {
            guard let vc = UIApplication.shared.keyWindow?.rootViewController else {
                return
            }
            let parent = UIViewController.forefrontViewController(vc)
            // 既にAlertControllerが表示中の場合は終了
            if parent is QUAlertController {
                return
            }
            if let alert = nextAlertController {
                parent.present(alert, animated: true) {
                    QUAlertController.removeQueue()
                }
            }
        }
    }

    /// QUAlertControllerの表示を実行、または表示登録します。
    open func show() {
        QUAlertController.addQueue(self)
        QUAlertController.showAlert()
    }

    /// UIAlertActionを追加
    ///
    /// - Parameters:
    ///   - title: ボタンタイトル
    ///   - style: ボタンスタイル
    ///   - handler: ボタンが選択された時のコールバック
    open func addAction(_ title: String, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)? = nil) {
        let action = UIAlertAction(title: title, style: style) { (sender) -> Void in
            if let aHandler = handler {
                aHandler(sender)
            }
            QUAlertController.showAlert()
        }
        super.addAction(action)
    }

    /// UIAlertController.addAction(action: UIAlertAction)による追加を防止。使用しないでください。
    ///
    /// - Parameter action: UIAlertAction
    override open func addAction(_ action: UIAlertAction) {
        assert(false, "Deprecated. use -addAction:title:style:handler:")
        return
    }
}

extension UIViewController {

    /// 最前面のViewControllerを取得します。表示中のViewControllerと一致するとは限りません。
    ///
    /// - Parameter viewController: 基準となるViewController
    /// - Returns: UIViewController
    class func forefrontViewController(_ viewController: UIViewController) -> UIViewController {
        if let vc = viewController.presentedViewController {
            return UIViewController.forefrontViewController(vc)
        }
        return viewController
    }
}

使い方

let alert = QUAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .Alert)

alert.addAction("キャンセル", style: .Cancel) { (_) in
    print("キャンセルが押された")
}

alert.addAction("おっけー", style: .Default) { (_) in
    print("おっけーが押された")
}

alert.show()

何か問題点などありましたら是非コメントください。

24
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
24