【Swift】URLSessionで非同期通信を実装する方法

こんにちは、のっくんです。

今日はSwiftのURLSessionの使い方について述べたいと思います。

URLSessionを使うと複数のファイルを非同期で同時にダウンロードすることができます。

ダウンロードするファイルが複数になると同期してダウンロードするのには時間がかかりますが、非同期処理を実装するとサクサク動くアプリを作れます。

非同期でXMLファイルを同時にダウンロードしてXMLパースするやり方を見ていきましょう。

Swiftは5.2、iOSは13.4です。

URLSessionを使わない場合

以下のように1つずつURLを取り出してXMLパースをかけていきます。

この実装だと処理速度が遅いです。

4つのURLがありますが、1つずつ順番にダウンロードしてパースしています。

順番に処理するのでURLの数が増えるにつれて、線形に時間が増えていきます。

URLSessionを使う方法(非同期処理)

URLSessionを使うと同時に処理できるので高速になります。

for文の中身は順番に実行されるのではなく、同時に実行されます。

URLが4つあるので4つのスレッドが割り当てられて同時に処理されます。

大まかなコードの流れは以下の通り。

  1. URLSessionを作成します。デフォルトのセッション構成にします。今回取得したデータはクロージャで処理するため、delegateはnilにしています。OperationQueue.mainを指定し、メインスレッドのキューを使うようにしています。
  2. タスクを作成します。completionHandlerはクロージャと呼ばれ、データのダウンロードが完了したときに呼ばれます。
  3. ダウンロードしたデータは変数dataに入っているので、XMLパーサに入れてパースします。

少しコードが多くなりましたが、これで複数のファイルのダウンロードが同時に実行できます。

処理結果を返すようにする

上記のコードではXMLパースして終了になっています。

パースした結果を何かの入れ物に入れて利用するにはどうすれば良いでしょうか。

1行目と17行目を追加しました。

パース結果をItemクラスに保存し、配列itemsに追加していくとします。

スレッドのタスクが終了したら配列itemsをcompletionに指定します。

こうすることで関数内の処理が終わったらitemsを関数の返り値としてリターンすることができます。

呼び出す側は以下の通り。

downloadPararrelではURLの数だけスレッドが実行されますが、スレッドの実行順序はランダムです。

各スレッドの処理が終わるとXMLパースの結果がreturnDataとして戻ってきます。

4つのスレッド処理が終わったタイミングでcompletionが呼ばれるので、completionは合計4回呼ばれることになってしまいます。

全てのスレッドの処理が終わってからデータを返すにはどうすれば良いのでしょうか。

DispatchGroupで非同期を管理する

上記の例だとスレッドの処理が全て終わらないままデータを返しているので、呼ぶ側としては使いづらいです。

全スレッドの非同期処理が完了するのを待ってからデータを返す方がベターです。

そういう場合にはDispatchGroupを使います。

DispatchGroupを使ってグループの動作を管理します。

グループを使用すると、一連のタスクを集約し、グループの動作を同期できます。 複数の作業項目をグループに関連付け、それらを同じキューまたは異なるキューで非同期実行するようにスケジュールします。 すべての作業項目の実行が完了すると、グループはその完了ハンドラーを実行します。 グループ内のすべてのタスクの実行が完了するのを同期的に待つこともできます。

https://developer.apple.com/documentation/dispatch/dispatchgroup

.enter()で各タスク(スレッド)の開始点を、.leave()で各タスク(スレッド)の終了点を決めます。

全てのタスクの非同期処理が終わった後に呼び出されるのが.notifyです。

この中で取得した結果を返すようにすれば、一度にまとめて返せます。

参考

・URLSessionについて

https://fluffy.es/download-files-sequentially/

たった2日でマスターするiPhoneアプリ開発集中講座 Xcode 11 Swift 5対応 (日本語) 単行本 – 2019/10/23

・DispatchGroupについて

https://developer.apple.com/documentation/dispatch/dispatchgroup

ABOUTこの記事をかいた人

のっくん

のっくん。理系院卒で大企業に就職。趣味は、読書、プログラミング、英会話、筋トレ、旅行。 Twitter:@yamagablog