直列処理でやりたいのに処理順序が狂う
Swiftでコードを書いていると、処理をシーケンシャルに直列に行いたいと思っているのに、なぜか前に書いてある処理を行ってくれず、先に書いてある処理が初めに開始されているかのように見えてしまうことがよくあります。
私が書いていた動画生成のコードでこのような箇所がありました。
HUD.show(.progress) let c = MovieCreator() c.createMovie(text: targetText, completion: { [weak self] (composedUrl, time) in self?.goPreview(composedUrl: composedUrl) })
HUDというのはこちらのライブラリPKHUDでして、端末の画面にくるくる回るインジケーターを表示して処理を行なっている最中であることを示すダイアログを表示します。
処理中のダイアログを表示させたあとに、後のMovieCireateクラスで、動画を生成させることにしていました。
つまり動画を生成している間、インジケーターを表示させておくという、とてもありきたりな処理です。
ところがこれをそのまま実行すると、先にcreateMovieメソッドが動き出し、程なくしてようやくインジケーターが回り出すというなんとも奇妙なことが起こりました。
DispatchQueueを使う
そこで、先に必ずインジケーターを表示させてからcreateMovieメソッドに取り掛かって欲しかったので、 DispatchQueueクラスを使うことにしました。
これにより、必ずインジケーターが表示されてから動画生成処理が動き出すようになりました。
ソースを以下に残しておきます。
let dispatchGroup = DispatchGroup() let dispatchQueue = DispatchQueue(label: "queue") dispatchQueue.async(group: dispatchGroup, execute: { DispatchQueue.main.async { HUD.show(.progress) } }) dispatchQueue.async(group: dispatchGroup, execute: { let c = MovieCreator() c.createMovie(text: targetText, completion: { [weak self] (composedUrl) in self?.goPreview(composedUrl: composedUrl) }) })
プログラミング作成はやはりある程度お手本となるソースががると効率よく勉強できますよね。
Udemyで紹介されているこちら↓のSwift講座は価格が安く、そして
- カメラ投稿
- 日出時刻検索
- ARアプリ
- AIアプリ
といったiPhoneならではの機能を使ったアプリをさくっと作れちゃうので、Swiftの初心者の方にはオススメですよ。私もあとでチェックしてみます!
【6日で速習】iOS 13アプリ開発入門決定版 20個のアプリを作って学ぼう(Xcode 11, Swift 5対応中)
どうして直列処理になるのか?
iOSにはGCD(Grand Central Dispatch)というマルチコアプロセッサ向け非同期処理を担う基盤があります。
この基盤があることにより、スレッドプール管理をプログラマー自身の手でやらなくてすむようにできています。なおソースコードはApache LicenseとしてAppleにより公開されています。
超絶ざっくり簡単に説明します。
GCDの仕組みとして、DispatchQueueというキューがあります。このキューを作成する時には「このキューは直列処理を行うキューですよ」「このキューは並列処理を行うキューですよ」というように、キューに対してどのような順番で処理させたいかを指定します。
そしてその生成されたキューに対して、ぽこぽこ処理を投げ込んでいくと、キュー生成時に指定した直列なのか並列なのかの指示によって順番に処理を動かすことができるという仕組みになっています。
並列処理タイプのキューを作る場合は以下の通りキューを生成します
// 並列処理タイプ // ディスパッチキュー優先度を指定しない let myQueue3 = DispatchQueue(label: "キュー3", attributes: .concurrent)
直列処理タイプのキューはこのとおりです
// 直列処理タイプ // ディスパッチキュー優先度を指定しない let myQueue4 = DispatchQueue(label: "キュー4")
ところで説明省いてるけれど、DispatchGroupって何?
先のコードでDispatchGroupというクラスが出てきていましたけれど、このDispatchGroupというものはなんでしょうか?
これは、DispatchQueueに投げ込んだ処理が全て終わったかどうかというようなことを判断したいときに使用するものです。
notifyメソッドを使うことで、DispatchGroup内の処理が全て終わったかどうかを判定することができます。サンプルコードです。
// 全ての非同期処理完了後にメインスレッドで処理 dispatchGroup.notify(queue: .main) { print("All Process Done!") }
参考資料