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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

Q&A

解決済

1回答

1724閲覧

Swiftの関数の戻り値の指定の仕方

sunglass

総合スコア303

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

0グッド

0クリップ

投稿2020/08/31 09:30

Cloud Firestoreから取得した数値を用いて計算(割り算)したいです。
その際に多分returnや戻り値の指定などあると思うのですがよくわからないです。。
現状下記のシンプルなコードで関数内では 10とprintされるのですが呼び出した先では10が表示されず計算できません。

詳しい方いましたらよろしくお願いします。

func getDocuments(){ let db = Firestore.firestore() db.collection("aaa").document("bbb").collection("ccc").getDocuments() { (querySnapshot, err) in if let err = err { print("Error getting documents: (err)") } else { for document in querySnapshot!.documents { if let count = querySnapshot?.documents.count{ self.aNumber = Double(count) // 10 self.amountNumber.text = "(count)" // 20 print(self.aNumber) // 10 } } } } } ... override func viewDidLoad() { super.viewDidLoad() getDocuments() // division & to String self.doneRateNumber.text = "(round( amountNumber / aNumber * 100))" ... }

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

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

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

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

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

guest

回答1

0

ベストアンサー

Cloud Firestore はいじったことがありませんが、ネットワークなどの非同期処理一般に言えることは

Swift

1 db.collection("aaa").document("bbb").collection("ccc").getDocuments() { (querySnapshot, err) in

上記の文のクロージャは、非同期で処理されています。

つまり、

Swift

1 // (1) 2 getDocuments() 3 4 // (2) 5 // division & to String 6 self.doneRateNumber.text = "(round( amountNumber / aNumber * 100))"

とした場合、(1) で処理を実行しても、(2) に到達する前に処理が完了している保証はありません。

言い方を変えれば、 クロージャで処理しているamountNumber(クロージャ内部だとself.amountNumber)に値が代入される前に (2) に到達することが十分にあり得るということです。

したがって、ラベルに値を反映させる処理もクロージャ内部に記述するか、あるいはgetDocuments()が処理完了後のクロージャなどを引数として取るようなメソッドとし、内部で渡されたクロージャの処理を任意のタイミングで行う、という方針を取ることとなります。

かなり抽象的なコードですが、たとえばこのような感じになるかと思います。

Swift

1// ここでは引数を1つ取り、戻り値を持たないクロージャを仮定。もちろん必要に応じて引数の個数や型を変更する 2func getDocuments(completion: @escaping (String) -> () ){ 3 // クロージャに渡したいデータ 4 let data = "done" 5 6 // 遅延の処理の代わりに DispatchQueue を使って1秒後に処理を行なっている。 7 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0 ){ 8 // クロージャに処理を行わせる 9 completion(data) 10 } 11 12 // 実際には次のようなパターンを採用する(これ以外もあり得る) 13 14 // (1)UI部品の更新を行わない場合 15 // completion(data) 16 17 // (2) クロージャ でUI部品の更新を行う(可能性がある)場合にはメインキューに入れて処理を行う 18 // DispatchQueue.main.async { 19 // completion(data) 20 //} 21 22} 23 24getDocuments() { data in 25 // クロージャで処理したデータは data に入ってくる。 26 27 // 実際にはラベルの更新などを行う 28 // label.text = text 29 print(data) 30} 31

詳細が分からないので間違っている可能性もありますが、実際のコードに反映させるならこのような感じとなります。

Swift

1func getDocuments(completion: @escaping (Int) -> () ){ 2 let db = Firestore.firestore() 3 db.collection("aaa").document("bbb").collection("ccc").getDocuments() { (querySnapshot, err) in 4 if let err = err { 5 print("Error getting documents: (err)") 6 } else { 7 for document in querySnapshot!.documents { 8 if let count = querySnapshot?.documents.count { 9 DispatchQueue.main.async { 10 completion(count) 11 } 12 } 13 } 14 } 15 } 16} 17 18... 19 20override func viewDidLoad() { 21 super.viewDidLoad() 22 23 getDocuments() { count in 24 self.aNumber = Double(count) 25 self.amountNumber.text = "(count)" // 20 26 print(self.aNumber) 27 } 28}

##2020年9月1日追記

1引数のクロージャには、下記のように他にもいくつかの書き方がありますので、わかりやすい方法を使っていただければと思います。

Swift

1getDocuments { data in 2 print(data) 3} 4 5getDocuments(completion: { data in 6 print(data) 7})

投稿2020/08/31 12:29

編集2020/09/01 04:04
TsukubaDepot

総合スコア5086

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

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

sunglass

2020/08/31 17:10

コメントありがとうございます! override func viewDidLoad() {...}内でこういう書き方もあるんですね。 指摘されている『到達する前に処理が完了している保証はありません。 』はその通りだと思いました。。 ちょっと全体のコードを見直して実装してみます。
TsukubaDepot

2020/09/01 04:33 編集

もしかしたら、クロージャの書式が viewDidLoad() 特有の書き方のような誤解を招いたかもしれません。 引数のないクロージャの書式の一つなのですが、見方によっては関数を定義しているようにも見える(実際は func キーワードがないので違う)ので、その点について追記しました。
sunglass

2020/09/01 04:29

(ありがとうございます!勘違いしてました、、)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問