お世話になっております。
seiftでMoyaを利用したhttp通信の結果を返すために、semaphoreを使い、非同期処理を同期的に処理するようなプログラムを実装しています。
しかし、ApiClientのrequestメソッドの完了ハンドラに書いてある処理が実行されません。
semaphoreを無くしたら動いたので、おそらくsemaphoreの使用方法がまずいのだと思いますが、どのように改善していけばいいでしょうか
試したこと
この記事に同じような問題の解決策が載っていましたが、これを参考にコードを変更してもうまく動きませんでした。
swift
1 func isLogin() -> Bool { 2 var isLogin = false 3 let semaphore = DispatchSemaphore(value: 0) 4 DispatchQueue.global(qos: .default).async { 5 ApiClient.shared.request(CheckTokenTargetType()) { result in 6 switch result { 7 case .success(_): 8 isLogin = true 9 10 default: 11 break 12 } 13 semaphore.signal() 14 } 15 } 16 semaphore.wait() 17 return isLogin 18 }
swift
1class ApiClient: ApiClientInterface { 2 private init() {} 3 4 static let shared = ApiClient() 5 6 func request<T>(_ request: T, completion: @escaping (Result<T.Response, MoyaResponseError>) -> Void) where T: ApiTargetType { 7 let provider = MoyaProvider<T>() 8 provider.request(request) { result in 9 switch result { 10 case let .success(response): 11 if let model = try? response.map(T.Response.self) { 12 completion(.success(model)) 13 } else { 14 completion(.failure(.unknownError)) 15 } 16 17 case let .failure(moyaError): 18 completion(.failure(moyaError)) 19 } 20 } 21 } 22}
非同期処理は非同期処理として処理すべきだと思います。
非同期処理で処理すると非同期処理の結果を戻り値として返せないと思うのですが、、、
非同期処理でもその結果を呼び出し元の関数が戻り値を返す前に返す方法などありますか??
非同期処理は、例えば Web API なら、ネットワークを通してサーバーにリクエストを送って、サーバー上で何か処理をして、結果が返ってくるわけで、どうしても時間がかかりますし、どのくらい時間がかかるかもわからない (サーバーの障害で返事が返らない可能性もあります) わけで、同期的に処理するということは、その間スレッドを停止して結果を待つことになります。特に、メインスレッドの場合はその間 GUI を止めて待つことになりますから、ユーザーから見るとアプリが固まったように見えてしまいます。
非同期処理というのは、リクエストを出したらすぐに制御を戻して、結果が返るまで例えばローディング中の表示にして待ち、結果が返ってきたらクロージャが呼ばれるのでそこで処理するという形になります。
アドバイスありがとうございます!
そのように実装していこうと思います。
一つ疑問なのですが、なぜ自分が投稿したコードでは非同期の部分が呼ばれないのでしょうか??
ApiClient.shared.request(CheckTokenTargetType()) { result in 〜 }
は、API リクエストを送信したらすぐに戻って semaphore.wait() します。そして、API の結果が返った時に { result in 〜 } の部分が実行されるはずですが、Moya のデフォルトの設定ではどうやらメインスレッドで実行することになってるようなので、isLogin メソッドの終了後に実行されるようにスケジュールされますが、isLogin メソッドは semaphore.wait() で止まってるために semaphore.signal() は実行されず、デッドロックすると思います。
ということはMoyaのリクエストの処理をバックグラウンドスレッドで行うようにすればsemaphore.signal()は実行されるという認識でよかったですか?
そうですね。バックグラウンドスレッドで UI 操作などをしなければ大丈夫だと思います。
ありがとうございます!!
バックグラウンドスレッドで実行するようにコードを変更してみました(コードを編集しました)が、状況は変化しませんでした。。
何かおかしなところはありますでしょうか??
回答1件
あなたの回答
tips
プレビュー