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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

3回答

4617閲覧

非同期処理の処理待ちで動作が止まる

bbb04

総合スコア18

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2017/11/11 05:40

Alamofireを使ってAPIリクエストをしています。レスポンスをSwiftyJSONを用いてパースした結果を返す関数を実装しようとしています。

https://qiita.com/kazuhirox/items/9ecb25bc238ad2d47ff0

の手法を用いて非同期処理の処理待ちをしているのですがループから抜け出せず
この関数の中で処理が止まっています。(printまで行ってません)

whileループのどのような処理を加えると抜けることができるのでしょうか。
非同期処理の理解が浅いのですがよろしくお願いします。

Swift3

1func getRain(latitude: Double,longitude: Double,time: Int) -> JSON{ 2 3~~~~~~~ 4 5 var keepAlive = true 6 var json:JSON = "" 7 8 Alamofire.request(url1,method: .get).responseJSON { (response) in 9 10 if let Json = response.result.value { 11 json = JSON(Json) 12 keepAlive = false 13 } 14 15 } 16 let runLoop = RunLoop.current 17 while keepAlive && 18 runLoop.run(mode: RunLoopMode.defaultRunLoopMode, before: NSDate(timeIntervalSinceNow: 0.1) as Date) { 19 } 20 print("json",json) 21 return json 22 23 24 25 }

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

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

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

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

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

MasakiHori

2017/11/13 08:19

getRain関数をメインスレッド上からDispatchQueue#syncなどで同期的に処理していませんか?
bbb04

2017/11/13 08:36

DispatchQueueは使って無いですが、別の非同期処理の中から関数呼び出しをしています。もしかしてこれが問題でしょうか。
MasakiHori

2017/11/13 08:54

whileループ内で print("waiting")などしてみるとどうなりますか? 出力され続けますか?
bbb04

2017/11/13 09:00

とめどなくwaitingが出力される状況です。
guest

回答3

0

確実に keepAlivetrueのままなだけなので、

swift

1 Alamofire.request(url1,method: .get).responseJSON { (response) in 2 3 defer { keepAlive = false } // 追加 4 5 if let Json = response.result.value { 6 json = JSON(Json) 7 // keepAlive = false 8 } 9 10 }

こうしましょう。

投稿2017/11/13 10:00

MasakiHori

総合スコア3384

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

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

bbb04

2017/11/13 10:28

ありがとうございます。試してみましたが変化なしですすみません...。 先にwhileの中に入ってしまうとどうしてもkeepAliveの値が更新されません。 (リクエストの部分の動作が止まっている?) whileの中でif(json != "nil"){keepAlive=false}なども試してみましたがダメでした。(json = "nil"は定義しました。)
bbb04

2017/11/14 05:08

本当にお騒がせしました。 別の非同期処理の中からgetRainの関数を呼び出していることが原因だったようで呼び出しの位置を外にしたら無事に処理待ちできました。 記載した場所外のミスで無駄なお時間をとらせてしまい申し訳ありません。
guest

0

動作確認してませんが、

swift

1while keepAlive { 2 runLoop.run(mode: .defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.1)) 3}

じゃないのかな。
run(mode:before:)は基本true返すみたいだし。

投稿2017/11/13 06:54

fuzzball

総合スコア16731

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

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

bbb04

2017/11/13 07:31

ありがとうございます。 実行してみましたが同じ結果になりました。 whileのループ内に入ってから非同期の方の処理が動いていないのでしょうか
fuzzball

2017/11/13 07:43

ありゃ。勘違いか‥。 runLoop.run(until: Date(timeIntervalSinceNow: 0.1)) だとどうですか? (fromageblancさんの15:57のコメントに書いてある修正はしておいて下さい。今のままだとエラーのときにfalseになりませんので)
bbb04

2017/11/13 07:57

試してみましたが違うようです... しかしさっきよりも出力(非同期ランスタート → エンド)までに時間差がありました。この間隔をもっと広げられたら値が取れるのでしょうか
fuzzball

2017/11/13 08:02

同期処理にするのではなく、非同期処理のままにすることをお勧めしますので、これ以上のコメントは控えます。(コードは元に戻して、fromageblancさんの回答に専念して下さい)
fromageblanc

2017/11/13 08:07

けっこうrun.loopは自分も使ってますので、該当のコードで問題ないと思うんですよね。 コピペ元同じだしw
bbb04

2017/11/13 08:35

お二人ともありがとうございます。 だいぶ長いコードになってきたのでもっと別の場所で間違ってるのかもしれません。見直してみます。
bbb04

2017/11/14 05:08

本当にお騒がせしました。 別の非同期処理の中からgetRainの関数を呼び出していることが原因だったようで呼び出しの位置を外にしたら無事に処理待ちできました。 記載した場所外のミスで無駄なお時間をとらせてしまい申し訳ありません。
guest

0

ベストアンサー

コード自体に誤りはないと思います。

このif文に入らないから抜けないのであり、調べるべきはGETで投げてるAPIの返す内容ですね。

Swift

1 if let Json = response.result.value { 2 json = JSON(Json) 3 keepAlive = false 4 }

投稿2017/11/11 09:42

fromageblanc

総合スコア2724

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

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

bbb04

2017/11/12 01:24

ありがとうございます。返信が遅れて申し訳ありません。 調べてみるとおっしゃる通りif文を通ってないようです。しかし、今まではif文に入っていたのですが処理待ちをしようとすると入らなくなりました。何が原因なのでしょうか。
fromageblanc

2017/11/13 00:42

該当のifの条件にkeepAliveは関係ないので処理待ちのコードを追加したことでif文に入らなくなるというのはおかしくないですか?
bbb04

2017/11/13 01:46

var json:JSON = "" var keepAlive = true Alamofire.request(url1,method: .get).responseJSON { (response) in if let Json = response.result.value { json = JSON(Json) print(json) keepAlive = false } } これだけならif文を通ってprintでコンソール出力できるようです。 しかし、whileループの部分を追加すると実行が止まります。
fromageblanc

2017/11/13 02:21

本当にこのifブロック内のprint("json",json)の出力ですか?他の場所でもprintしてませんか? ifブロック内に入ってればwhile文には入らず処理を抜けるはずなんですが… whileループを書くと止まる(というかウェイトになる)のはifブロックに入ってないからです。 何か見落としてると思いますよ
bbb04

2017/11/13 06:38

他のところでの出力はしていないのでここの出力で間違い無いと思います。 print("非同期ランスタート") Alamofire.request(url1,method: .get).responseJSON { (response) in if let Json = response.result.value { json = JSON(Json) keepAlive = false print(json) } } /* while keepAlive && runLoop.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.1)){ print("run") } */ print("非同期ランエンド") return json やはりここまでならif文は通るのでwhileの中から抜け出せないようです。 whileに入ってからAPIのリクエスト(非同期の動作)が止まるということはありえますかね。重ね重ねすいません
bbb04

2017/11/13 06:40

この状態(whileを除く)の出力はこんな状態です。 非同期ランスタート 非同期ランエンド getRain-end { "ResultInfo" : { "Total" : 1, "Status" : 200, "Start" : 1, "Latency" : 0.013998999999999999, "Count" : 1, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fromageblanc

2017/11/13 06:57

keepAliveのフラグを返すところはresponseブロックの最後じゃないですかね… 試してみてください。 Alamofire.request(url1,method: .get).responseJSON { (response) in if let Json = response.result.value { json = JSON(Json) // keepAlive = false responseブロックの最後に移動 print(json) } keepAlive = false }
bbb04

2017/11/13 07:28

試してみましたが、特に変化は無いみたいでずっとwhile内でリクエストを待ってる状態です。 whileの位置が悪いということはありますかね
fromageblanc

2017/11/13 07:56

whileの位置は正しいですよ。不思議ですねぇ。keepAliveがfalseになった時点で、run.loop云々の条件は評価せずにwhileにははいらないはずなんですが。
fromageblanc

2017/11/13 13:23

やはり、keepAlive = false の位置はresponseブロック終了直前に置くべきですよ。 if let Json ... のブロック内に書いてしまうと、result.valueがnilの場合、ずっとウェイト状態になってしまいます。 responseの内容はとりあえずおいといて、このコードで”非同期ランエンド”はやはり出ませんでしょうか? Alamofire.request(url1,method: .get).responseJSON { (response) in if let Json = response.result.value { json = JSON(Json) print(json) } keepAlive = false } while keepAlive && runLoop.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.1)){ print("run") } print("非同期ランエンド") return json
bbb04

2017/11/13 14:46

こんな時間までありがとうございます。 コンソール出力でひたすらrunが出力されます... let now = getNowClockString() var intnow:Int = Int(now)! if(intnow%5 != 0){ intnow -= intnow%5 } intnow += time let strlat:String = String(latitude) let strlon:String = String(longitude) let url1 = "https://map.yahooapis.jp/weather/V1/place?coordinates="+strlon+","+strlat+"&appid="+YolpKey+"&output=json&past=1&interval=5&date="+now var json:JSON = "nil" var keepAlive = true let runLoop = RunLoop.current まさかとは思いますが変数宣言でおかしい部分があるのでしょうか。 見にくいかとは思いますが見ていただけると助かります。 getNowClockStringは現在時間を取得する関数です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問