データ変換をするクラスを作って、処理中にその中で変更される進捗度合いを、KVOで UIAlertController上のUIProgressViewに反映させます。
最初、進捗に応じた UIProgressView の表示更新ができなかったんですが、以下のように
表示側には DispatchQueue.main.async(flags: .barrier) {}
、
処理側には、 DispatchQueue.global(qos: .background).async {}
を入れることで解決できました。
// progressView と _observer はメンバ変数
let progressAlert = UIAlertController(title: "Please wait", message: "Converting from old to new", preferredStyle: .alert)
self.progressView.progress = 0.0
progressAlert.view.addSubview(self.progressView)
// UIAlertControllerの高さ変更とUIProgressViewの配置
let height:NSLayoutConstraint = NSLayoutConstraint(item: progressAlert.view!,
attribute: NSLayoutConstraint.Attribute.height,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1, constant: 100)
progressAlert.view.addConstraint(height)
self.progressView.translatesAutoresizingMaskIntoConstraints = false
self.progressView.leadingAnchor.constraint(equalTo: progressAlert.view.leadingAnchor, constant: 10.0).isActive = true
self.progressView.trailingAnchor.constraint(equalTo: progressAlert.view.trailingAnchor, constant: -10.0).isActive = true
self.progressView.topAnchor.constraint(equalTo: progressAlert.view.topAnchor, constant: 65.0).isActive = true
self.progressView.heightAnchor.constraint(equalToConstant: 2.0)
// present と observe 設定と終了処理
present(progressAlert, animated: true, completion: {
let dataMigration = DataMigration()
self._observer = dataMigration.observe(\.dataProgress, options: .new) { object, change in
DispatchQueue.main.async(flags: .barrier) {
self.progressView.setProgress(object.dataProgress, animated: true)
}
}
dataMigration.convert(<何かオプション>, completionHandler: {(sucess)->Void in
self._observer = nil
if sucess {
print("Convert Complete")
} else {
print("Error")
}
progressAlert.dismiss(animated: true, completion: {
... 終了時の処理 ...
})
})
})
observeをするためには、DataMigrationは NSObjectのサブクラスでなければなりません。
class DataMigration: NSObject {
@objc dynamic var dataProgress: Float = 0.0
func convert(options: [Any], compleationHandler:@escaping ((_ success: Bool) -> Void) ) {
var numberOfData: Float = ...データの個数...
var countData: Float = 0.0
DispatchQueue.global(qos: .background).async {
for ...numberOfData分の繰り返し... {
...何か処理...
countData += 1
self.dataProgress = countData / numberOfData
}
completionHandler(true)
}
}
}
参考にしたのは下記です。
StackOverflow: Add Progress bar to UIAlertController with showing update