質問: data } } return rs } } ```
回答: あなたのコードでせっかく書いたプログレスバー更新処理がうまくいかないのはこの部分のせいです。 ``` DispatchQueue.global(qos: .default).sync { //---★ ``` `sync`メソッドは呼び出し側のスレッド(今の場合メインスレッド)をブロックしてしまい、せっかく並行処理可能な`global`キューで実行しても、`DispatchQueue.main.async {...}`のところでメインキューに入れられた`self._viewProgress.setProgress(Float(i + 1) / Float(rs.count))`は、ずっとメインキューの中で順番待ち、あなたのコードで言うと`btnAction_Tap(_:)`の処理が完了するまで実行されません。 メインキューで行わなければいけない処理をブロックしないようにするためには、非同期処理を使って、「この部分は後で」あるいは「この部分は裏で(非同期に並列して)」と言うことだけ指定したら、さっさと`btnAction_Tap(_:)`を終了しないといけません。 言葉で言うと大変なことをさせられるように見えるかもしれませんが、あなたのコードの場合、典型的な定石通りの完了ハンドラーを使うパターンに簡単に書き換えられます。 (質問文中には説明されていないメソッド等があるので、若干修正しないと使えないかもしれません。) ``` /// ボタン押下時処理 @IBAction func btnAction_Tap(_ sender: UIBarButtonItem) { //プログレスバーを表示 _viewProgress.setProgress(0.0) _viewProgress.isHidden = false //ファイル作成 createFile() //---(1)へ //下に書いた理由と同じで、ここに何か処理を書くと、完了ハンドラーより先に実行されてしまう } /// (1) ファイル作成処理 func createFile() { //ファイル出力 getData{ rs in //---(2)へ <-- 非同期処理の結果は戻り値で受け取ろうとせず、クロージャーで拾う let filePath: String = self.outputFile(rs) //tmpフォルダに出力 //(出力成功) if filePath != "" { let file = URL(fileURLWithPath: filePath) let handler: ((Bool) -> Void) = { completed in if completed { print("処理完了") } self._viewProgress.dismiss() } //ダイアログ(UIActivityViewController)を表示 self.showDialog(self, activityItems: [file as AnyObject], handler: handler) //(出力失敗) } else { //〜エラーメッセージ表示〜 } } //<- 「この部分(完了ハンドラー)は後で」(処理完了後に)実行するのを登録されるだけで`getData(completion:)`はすぐに終了する //従ってこの部分にコードを書いてしまうと完了ハンドラーより先に実行されてしまうので注意 } /// (2) データ加工処理 func getData(completion: @escaping ([[String : String]])->Void) { //加工元のレコードセットを取得 var rs: [[String : String]] = getOrgData() DispatchQueue.global().async { //<- ここで同期メソッドを呼んでは意味がない、必ず`async`を使う //ループしてレコードを1行ずつ処理 for i in 0 ..< rs.count { //進捗表示 DispatchQueue.main.async {//<- いくらここでメインキューに処理を入れてもメインキューが停止中だと意味がない self._viewProgress.setProgress(Float(i + 1) / Float(rs.count)) } var data = rs[i] //〜データの加工をゴリゴリ〜 rs[i] = data } completion(rs) //<- 非同期処理の結果は戻り値にせずに完了ハンドラーに渡すというのが定石の一つ } //<- 「この部分は裏で」実行するよう登録されるだけで`DispatchQueue.global().async`自体はすぐに終了する } ``` ちなみにあなたのコードの使い方では`[unowned self]`は不要(循環参照になる心配はない)なので、省かせてもらっています。どんな場合に「循環参照になる心配はない」のかがよくわからないのであれば`[unowned self]`ではなく`[weak self]`を使った方がいいでしょう。`unowned`は使い方を間違えるとアプリが簡単にクラッシュしてしまいます。 コメントには他にも色々書いていますが、とりあえずあなたのコードに当てはめて動きを確かめてもらってから意味を考えた方がいいかもしれません。