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

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

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

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

Q&A

0回答

998閲覧

API処理を利用して戻り値のあるメソッドを作る方法

tomaa

総合スコア84

Swift

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

0グッド

0クリップ

投稿2020/11/09 08:36

編集2020/11/09 08:37

前提・実現したいこと

SwiftUIと、Django REST Frameworkを利用してiOSアプリを開発しています。

GETHTTPメソッドでAPI接続をして、ある値を取得し、その値である計算をして、計算結果を戻り値として変えるメソッドを作りたいです。

引数で指定した2つの数字をAPIで取得し、それぞれを足してその合計値を返すメソッドを以下のようになコードで作成していますが、うまく機能しません。

取得した数値に計算がされず、戻り値に指定している変数の初期値がリターンされてしまいます。

どのように改善すれば、目的の動作となるでしょうか?

該当のソースコード

viewModel

class AppState: ObservableObject { @Published var numbers:[Numbers]? func getTotalNumber(firstNo:Int,secondNo:Int ) -> Int { // Set up the URL request var totalNo:Int = 0 let endpoint: String = "https://sample.com/api/?firstNo=(firstNo)&secondNo=(secondNo)" print(firstNo) // 1 print(secondNo) // 2 let url = URL(string: endpoint) let urlRequest = URLRequest(url: url!) // set up the session let config = URLSessionConfiguration.default let session = URLSession(configuration: config) // make the request let task = session.dataTask(with: urlRequest) { (data, response, error) in // check for any errors guard error == nil else { print("error calling GET") return } // make sure we got data guard let responseData = data else { print("Error: did not receive data") return } // parse the result as JSON, since that's what the API provides DispatchQueue.main.async { do{ self.numbers = try JSONDecoder().decode([Numbers].self, from: responseData) for number in self.numbers!{ totalNo += number.number } }catch{ print("Error: did not decode") return } } } task.resume() print(totalNo) //3を期待するが0と表示される return totalNo } }

JsonModel

struct Numbers:Codable,Identifiable { var id: Int var number: Int }

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

Xcode:Version 12.0.1

DjangoRESTframework: 3.12.1

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

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

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

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

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

TsukubaDepot

2020/11/09 11:05

一般的な話をすると、非同期なクロージャに取り込まれたブロック外のプロパティ(self.をつけるようにコンパイラに指示されるプロパティ)は、実際にはいつ更新されるかわからないため、ご提示いただいたコードのように記述してもうまく更新することはできません。 つまり、 let task = session.dataTask(with: urlRequest) { でdataTask を開始し、その中で totalNo += number.number と更新したところで、ブロック外にある return totalNo の方が先に実行されるため0となってしまいます。 一般的な解決策は https://teratail.com/questions/299401 に書いてありますので、そちらを参考にしていただければと思います。 ただ、上記のことを回答欄に書かなかったのには理由があります。 非同期処理内で JSONDecoder() から返される値を代入しているプロパティは @Published var numbers:[Numbers]? と @Published 属性付きで宣言されていますが、私が SwiftUI 関連のこの辺りの扱いをよく把握していないため、全体的な影響まで把握できないためです(万が一不都合が起こっても切り分けできないため)。 なので、あくまで参考意見ということで実験していただければとおもます。
tomaa

2020/11/09 11:56

コメントいただきありがとうございます。 ご丁寧に解説していただきありがとうございます。こちらの内容参考にさせていただき解決にできるよう方法を試してみようと思います。
TsukubaDepot

2020/11/09 12:04

参考先リンクに挙げた例は、クロージャを使って非同期処理実行後の処理を記述する例ですが、たとえば JSON でのデコードが完了し、その値をなんらかのプロパティに入れた時点で処理を実行させる(いわゆるプロパティオブザーバ)でも実現可能だと思っています。 その方法が、たとえばSwiftUIで使われるようなプロパティ監視の枠組みで実現できるようであれば、それが一番自然ではないかと思っています。
tomaa

2020/11/09 12:06

なるほど、ご丁寧に教えていただきありがとうございます! 解決への良いアドバイスとなりそうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問