🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Xcode

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

Swift

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

Q&A

解決済

1回答

1085閲覧

swift Firebaseから取得したデータを配列に格納したい

sihi

総合スコア7

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Xcode

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

Swift

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

0グッド

1クリップ

投稿2019/12/10 16:31

前提・実現したいこと

Firebaseに格納されているデータを取得してきて、配列に格納して利用したいのですが、
配列に格納できません。厳密に言うと格納はできるのですが、その配列を利用することができないと言うか、格納されているようで実際には格納されていないと言うか、言葉で説明するのが難しいので、下のコードと一緒に説明します。

プログラミング初心者で基本的な部分がわかっていないのが原因だと思うのですが、調べ方も悪いのか、自分ではどうしようにも解決できなかったので質問させていただきました。

FirebaseのDBはこちらになります。
イメージ説明

プログラム1

swifrt

1class ViewController: UIViewController { 2 3 var DBRef: DatabaseReference! 4 var users: [String] = []//Firebaseのデータの格納先の配列 5 6 override func viewDidLoad() { 7 super.viewDidLoad() 8 DBRef = Database.database().reference() 9 let defaultPlace = DBRef.child("users")//users以下のデータを取得 10 defaultPlace.observe(.value ) { 11 (snap: DataSnapshot) in 12 self.users = snap.value! as! [String]//メンバ変数?に取得したデータを代入 13 print(self.users)//["太郎","次郎","三郎"]と出力される 14 } 15 } 16}

プログラム2

swifrt

1class ViewController: UIViewController { 2 3 var DBRef: DatabaseReference! 4 var users: [String] = []//Firebaseのデータの格納先の配列 5 6 override func viewDidLoad() { 7 super.viewDidLoad() 8 DBRef = Database.database().reference() 9 let defaultPlace = DBRef.child("users")//users以下のデータを取得 10 defaultPlace.observe(.value ) { 11 (snap: DataSnapshot) in 12 self.users = snap.value! as! [String]//メンバ変数?に取得したデータを代入 13 } 14  print(self.users)//[]が出力される 15 } 16}

プログラム2でprint文をdefaultPlace.observe(.value){}の外部に出したところ、空の配列が出力されてしまいました。

つまり、defaultPlace.observe(.value){}の内部でしか、usersにデータが格納したことになっていないということなのだと考えたのですが、この考えで間違いはないでしょうか...

私がやりたい事は、プログラム2でも["太郎","次郎","三郎"]が出力される事です。
どういった記述をすれば、それが実現できるのでしょうか。

わかりにくい説明で大変申し訳ないのですが、アドバイスよろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

defaultPlace.observe(.value){}の内部でしか、usersにデータが格納したことになっていない

結果的にはあっています。 observe(.value) { (snap: DataSnapshot) in ... } は、データの読み取り (observe = 観測) が完了したら、 { ... } の中の処理を行う、というメソッドです。「非同期処理」でググってください。

defaultPlace.observe(.value ) { (snap: DataSnapshot) in ... } をした時点では、まだ読み取りが完了していません。この行の処理は終わっていませんが、次のprint文に進みます。まだ self.users には何も入っていません。
その後、読み取りが完了したら、 { ... } の処理が始まります。ここで初めて、 self.users が上書きされます。

投稿2019/12/10 16:47

thyda.eiqau

総合スコア2982

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

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

sihi

2019/12/10 17:24

ご回答ありがとうございます。 今少し、非同期処理について調べてみたのですが、プログラム2の{}外部のprintが非同期処理が完了する前に行われるため、配列に何も入っていない状態で出力されるというところまでは理解できました!ありがとうございます。 つまり、ViewDidLoad()内で、何らかの非同期処理の完了を待機する処理を記述して、その後にprint文を書けばいいという考えで良いのでしょうか。
thyda.eiqau

2019/12/10 17:29

それでも動くのは動くと思いますが、viewDidLoadはメインスレッドで処理されるため、ここで処理を待つようにすると画面の描画も止まってアプリがフリーズしたように見えます。 どのように表示したいか次第ですが、非同期処理はとりあえずやり始めておいてviewDidLoadの処理は先にすすめる(いったん空で描画するか、インジケーターをくるくる回しておく)、その後、読み込みが完了したときに描画をしなおす(空で描画してたところに太郎が出るようにする、くるくるを止める・消すなど)するのが常套手段と思います
sihi

2019/12/12 09:09

おかげさまで、やりたかったことができました。 とても勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問