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

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

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

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

Swift

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

Q&A

解決済

1回答

851閲覧

SwiftのConcurrency利用時の待機について

thirdesr34

総合スコア36

非同期処理

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

Swift

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

1グッド

0クリップ

投稿2022/08/01 06:42

前提

SwiftとUIKitを利用してiOSアプリを作成しています。
利用しているライブラリの関数でasyncキーワードの付いているものがあり、その結果をどのように受け取るか不明なので知りたいと思っています。
色々とConcurrencyについて調べたのですがうまく解決できないため、質問させてください。

実現したいこと

UIApplicationDelegateのファイルを開いた際のデリゲートメソッドapplication(_:open:options:)では、ファイルを正常に開けた場合はTrueを返すことになっています。
このメソッドの内部で、ライブラリの関数を用いて結果を得て、その結果をもとに戻り値を返したいと思っています。

発生している問題

ライブラリの関数側では、関数の定義にasyncキーワードが付いているため、呼び出し側ではawaitを付けて呼ぶか、Task節で囲う必要があると理解しています。ただ、これらの方法はどちらも難があります。

Swift

1//ライブラリ側関数の定義 2func getValue(_ url: URL) async -> Int

1.単にawaitを付けて呼ぶライブラリの関数を呼び出す場合
メソッド内部でawaitを利用すると、そのメソッド自体にasyncをつける必要が発生しますが、UIKit側に定義されているapplication(_:open:options:)と異なってしまうため、呼び出し元のメソッド自体にasyncをつけることはできません。

Swift

1 func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 2 let result = await library.getValue(url) 3 if (result == 1) { 4 return true 5 } 6 return false 7 }

2.Task節で囲ってライブラリの関数を呼び出す場合
awaitを付けて呼び出すよう記述しても、Task節自体はapplication(_:open:options:)メソッドの実行時ではなく非同期的に実行されると思われるため、下記のコードでは常にfalseを返してしまいます。

Swift

1 func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 2 Task{ 3 let result = await library.getValue(url) 4 if (result == 1) { 5 return true 6 } 7 } 8 return false 9 }

おそらくTask節の終わりの方が筋が良いと思いますが、ライブラリ関数の実行が完了するまで待機しておき、ライブラリ関数の戻り値を得てからメソッドの戻り値を返すようにするには、どのように記述すればよいでしょうか。
または、Task以外により良い記述の仕方があれば教えてください。

補足情報(FW/ツールのバージョンなど)

Xcode 13.4.1
Swift 5.6.1

退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

Swift Concurrencyは、非同期処理を同期処理に変換するものではなく、同期処理のような書き方で非同期処理を書けるようにする(実際に動きは非同期処理で動く)やり方です。

非同期処理を同期処理に変換したかったら、次の記事にあるようにDispatchSemaphoreを使って非同期処理の完了を待ち合わせる処理が必要です。
https://qiita.com/shtnkgm/items/d552bd3cf709266a9050

ただ、 application(_:open:options:) で受け取ったurlを使用してアクセスしようとしているファイルは、実際にはローカルファイルではないですか?

ローカルファイルなら、非同期でファイルを読み込む必要はないので、次の優先順でやり方を探れば良いと思います。

  1. このライブラリがasync仕様(非同期仕様)のgetValueだけでなく、同期仕様の(呼び出しが戻ったら値を取得できている)getValueメソッドを提供していないか探し、あれば同期仕様のgetValueメソッドを使用する。
  2. このライブラリに自分で手を入れることができるなら、同期仕様のメソッドを自分でライブラリに追加する。
  3. このライブラリに自分で手を入れることができないなら、このライブラリを使用せず自分でローカルファイルにアクセスする。
  4. どうしてもこのライブラリでアクセスする必要があるなら、前述の方法で非同期処理のgetValueを同期処理に変換する。

アクセスしようとしているファイルがネットワークにアクセスして取得するファイルなら、そもそも同期処理すべきではありません。

その場合は、 application(_:open:options:) は一旦trueを返してurlの受け取りだけ行い、その後非同期処理でネットワークにアクセスしてファイルを受け取り、受け取りができなかったら、エラーの原因(ネットワーク障害等)を示して、それを排除してユーザーにリトライを促すようなメッセージを表示すべきだと思います。

投稿2022/08/03 13:08

TakeOne

総合スコア6299

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

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

thirdesr34

2022/08/03 13:23

大変有難うございました。await/asyncが実際には同期処理ではない点について頭から抜けていたようです。セマフォを使ってみたいと思います。 尚、ファイルの場所による特性を考慮する部分や、そもそも同期処理すべきかどうかの点についてもご指摘いただき助かりました。アプリ側で同期処理を行うべきかなど、改めて見直してみたいと思います。有難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問