質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

4回答

696閲覧

2つの重い処理を直列に実行したい(SVProgressHUDを使いたい)

HajimeHamada

総合スコア20

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

3クリップ

投稿2018/03/30 00:28

編集2018/03/30 00:30

まず、やりたいことのイメージを表すためにcodeを示します。

Swift

1 SVProgressHUD.show(withStatus: "Start1") 2 DispatchQueue.global().async { 3 sleep(5) 4 print("DEBUG_PRINT: Done1") 5 DispatchQueue.main.async { 6 SVProgressHUD.dismiss() 7 } 8 } 9 10 SVProgressHUD.show(withStatus: "Start2") 11 DispatchQueue.global().async { 12 sleep(5) 13 print("DEBUG_PRINT: Done2") 14 DispatchQueue.main.async { 15 SVProgressHUD.dismiss() 16 } 17 }

つまり、code中ではsleep(5)で示している重い処理が2つあり、それらを順に実行して、それぞれでSVProgressHUDを用いてIndicatorを回したいということです。非同期の扱いがよくわかっていないため、どのようにすればいいかの見当がつきません。ネットを見て「セマフォを使うのかなあ?」などといろいろやってみたのですが、うまくいっていない状況です。

ご教示ください。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

質問のコードだと、SVProgressHUD.show(withStatus: "Start1")の直後にSVProgressHUD.show(withStatus: "Start2")が実行されてしまいます。

なんか難しく考え過ぎているような気が。

swift

1DispatchQueue.global().async { 2 //#1 3 DispatchQueue.main.async { 4 SVProgressHUD.show(withStatus: "Start1") 5 } 6 sleep(5) 7 print("DEBUG_PRINT: Done1") 8 DispatchQueue.main.async { 9 SVProgressHUD.dismiss() 10 } 11 12 //#2 13 DispatchQueue.main.async { 14 SVProgressHUD.show(withStatus: "Start2") 15 } 16 sleep(5) 17 print("DEBUG_PRINT: Done2") 18 DispatchQueue.main.async { 19 SVProgressHUD.dismiss() 20 } 21}

でいけませんかね?
(SVProgressHUDを呼び出しているところはsyncでもいい‥はず)

投稿2018/03/30 08:35

fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HajimeHamada

2018/03/30 10:07

回答ありがとうございます。動作することを確認しました。 全体をglobalキューに入れて、mainキューで実行するものだけ指定する、ということですね? わかりやすいです。 いろいろなやり方があるものですねえ。 ありがとうございました。
guest

0

愚直にやるとしたら下記のような方法でできるかと思います。

Swift

1SVProgressHUD.show(withStatus: "Start1") 2DispatchQueue.global().async { 3 sleep(5) 4 print("DEBUG_PRINT: Done1") 5 DispatchQueue.main.async { 6 SVProgressHUD.dismiss() 7 SVProgressHUD.show(withStatus: "Start2") 8 DispatchQueue.global().async { 9 sleep(5) 10 print("DEBUG_PRINT: Done2") 11 DispatchQueue.main.async { 12 SVProgressHUD.dismiss() 13 } 14 } 15 16 } 17} 18

ただこれだと見づらいので
中の処理をメソッドに分けたり、
下記のようなライブラリが色々ありますので、ライブラリの導入なども検討してみると良いかなと思いました。

https://github.com/mxcl/PromiseKit

投稿2018/03/30 03:22

編集2018/03/30 08:02
newmt

総合スコア1277

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HajimeHamada

2018/03/30 08:03

回答ありがとうございます。所望の動作をすることを確認いたしました。 なるほど、入れ子にしていくわけですね。非同期処理に慣れておらず、頭がついていかないところがありますが、ライブラリも含めて勉強していきたいと思います。ありがとうございました。
guest

0

こんにちは!
GCDのキューには処理を順番に実行するシリアルキューと、複数同時に実行するコンカレントキューがありあます。
DispatchQueue.global()
というコードはグローバルな(システム組み込みの)”コンカレント”キューを返してくれます。
メインキュー以外のシリアルキューは自分で生成します。

swift

1let serialQueue = DispatchQueue(label: "mySerial") //シリアルキュー 2let concurrentQueue = DispatchQueue(label: "myConcurrent", attributes: .concurrent) //※ご参考コンカレントキュー

このコードのようにattributesに.concurrentを明示的に指定"しなければ"シリアルキューを作ることができます。
今回のケースであれば

serial

1let serialQueue = DispatchQueue(label: "mySerial") // シリアルキュー 2 serialQueue.async { 3 DispatchQueue.main.async { 4 SVProgressHUD.show(withStatus: "Start1") 5 } 6 sleep(5) 7 print("DEBUG_PRINT: Done1") 8 DispatchQueue.main.async { 9 SVProgressHUD.dismiss() 10 } 11 } 12 13 serialQueue.async { 14 DispatchQueue.main.async { 15 SVProgressHUD.show(withStatus: "Start2") 16 } 17 sleep(5) 18 print("DEBUG_PRINT: Done2") 19 DispatchQueue.main.async { 20 SVProgressHUD.dismiss() 21 } 22 }

これでキューに入れた順番での処理の実行がキューの特性により保証されます。
SVProgressHUDを実際にいれてテストしてみたのでこれでOKだと思います!

投稿2018/03/30 03:33

編集2018/03/30 07:19
516k

総合スコア189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

516k

2018/03/30 04:11

SVProgressHUDがわかっていませんでした。このコードでは質問者さんのやりたいことが実現できません。はやとちりで回答して申し訳ありませんでした。 既に削除申請しております。
516k

2018/03/30 07:26

teratailさんが削除してくれなかったので、一応SVProgressHUDというのを入れてみてテストしてみました。おそらく質問者さんがやりたかったことはこれで実現できていると思います。 ネストが深くなりすぎないレベルなら私個人としてはnewmtさんの回答のように入れ子にしていくのが読みくだしやすく、バグも混入しづらいと思います。
HajimeHamada

2018/03/30 07:59

回答ありがとうございます。SVProgressHUDまで試していただいたようで、恐縮です。 なるほど、シリアルキューを作って、その中にメインキューの処理を入れていくということですね?そうであれば、頭のなかで理解しやすいです(考え方が間違っていたら、ご指摘ください)。参考にさせていただきます。 ありがとうございました。
516k

2018/03/30 08:51

重たい処理は全てシリアルキューのバックグラウンドスレッドで実行し、UI関連の処理だけをメインキューで実行するイメージです。 今回のケースであればUI関連の処理とはSVProgressHUDの表示、非表示ですね。
guest

0

複数のプログラムを直列に実行(順に実行)するのが同期実行、同時並行に実行(実行順は制御できない)するのが非同期実行です。

質問者は「順に実行したい」のですから、非同期実行(DispatchQueue.global().async )ではなく、同期実行(DispatchQueue.global().sync )を使えば良いと思います。

投稿2018/03/30 01:38

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HajimeHamada

2018/03/30 03:06

回答ありがとうございます。 2つのDispatchQueue.global().asyncをDispatchQueue.global().syncに変更してみました。重い処理(sleep)の順番は問題なく、(5秒スリープ)→「Done1」表示→(5秒スリープ)→「Done2」表示と動作するようになったのですが、SVProgressHUDのIndicatorが全く表示されません。 同期・非同期の話とともに、SVProgressHUDの使い方の話もあるようなのですが、何かわかりますでしょうか?
fuzzball

2018/03/30 04:24

メインスレッドに処理が回ってないんじゃないかなぁ。asyncの中で、2つの処理をsyncすればいいのかな。
516k

2018/03/30 07:40

SVProgressHUD.show(withStatus: "Start1") SVProgressHUD.show(withStatus: "Start2") を呼び出しているスレッドはメインスレッドのはずなので、syncを呼び出せばメインスレッドがロックしてHUDが表示されなくなるのは、ある意味正しい(想定通りの)振る舞いですね。 fuzzballさんの指摘のようにDispatchQueue.global().asyncのブロック内でsyncを呼び出すと、今度はバックグラウンドスレッドがロックするのでメインスレッドで正しくHUDが表示されると思います。 個人的にはsyncを使うのその呼び出し元のスレッドがバックグラウンドスレッドであることが100%保証されている場合に限定した方がいいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問