2018年4月19日木曜日

UIAlertController の handler 内で UI の描画処理を行いたい場合に注意すること

概要

UIAlertController は iOS 上でアラートを表示するためのクラスです
基本的な使い方は Web 上に転がっているのでそれらを参考にしてください
もしくは自分の記事もあります -> こちら

UIAlertController はボタンを押したときの処理を handler にクロージャとして記載することができます
ただこの handler 内で UI の操作や描画行おうとする上手くいかないことがあります
自分の場合は handler 内で UIActivityIndicatorView の startAnimating と stopAnimating をしようとしたのですがハマったのでその対策方法を紹介します

環境

  • macOS 10.13.4
  • Xcode version 9.3 (9E145)
  • Cocoapod 1.4.0

方法

答えとしては DispatchQueue を使います
UI の描画はメインスレッドで行い、それ以外の処理はバックグラウンドで処理させるようにします

let defaultAction: UIAlertAction = UIAlertAction(title: "初期化", style: UIAlertActionStyle.destructive, handler:{
    (action: UIAlertAction!) -> Void in
    // インジケータ表示
    self.indicator.isHidden = false
    self.indicator.startAnimating()
    DispatchQueue.global(qos: .default).async {
        // 何か処理
        self.doSomething()
        DispatchQueue.main.async {
            // インジケータ非表示
            self.indicator.stopAnimating()
            self.initView()
        }
    }
})

ポイントは 3 つあります
まずインジケータの開始は DispatchQueue の外で行います
当然ですが DispatchQueue.global(qos: .default).async 内で UI の操作を行うと怒られるためです

DispatchQueue.global(qos: .default).async 内ではアラート画面のボタンが押されたときの処理を描きます
具体的には Realm などのデータベース処理や Firebase などのクラウド処理を記載します

そしてそれらの処理が完了したら DispatchQueue.main.async でメイン処理に戻りインジケータの停止とその他の UI の描画を行っています
DispatchQueue.main.async の処理は必ずロジック側の処理が完了してからコールされます

参考サイト

0 件のコメント:

コメントを投稿