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

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

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

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

iOS

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

Swift

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

Q&A

解決済

1回答

388閲覧

【Swift】Firebaseからデータを取得する処理の順番がおかしい

nekokichi

総合スコア54

Firebase

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

iOS

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

Swift

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

0グッド

0クリップ

投稿2019/02/05 03:14

Firebaseから文字列のデータを取得して、それを配列に格納し、カスタムセル上のUILabelに格納する処理を作ろうとしています。

当初は、ViewDidLoad内でデータを取得すれば、自然にカスタムセルで正常にデータが表示されると思っていました。

しかし、下記のコードで各処理の順番を出力したら、下記のような結果になりました。

「結果」
1
2
4
6
3
3
5

どうしてviewDidLoad内にあるはずのloadNotification()(データを取得する関数)は、最初にスルーされて、後から実行されるのでしょうか?

データ取得が完了するまで次の処理には行かないようにするにはどうすればいいのでしょうか?

Swift

1 override func viewDidLoad() { 2 super.viewDidLoad() 3 4 print("1") 5 loadNotification() 6 print("6") 7 8 tableView.register(UINib(nibName: "NotificationCell", bundle: Bundle.main), forCellReuseIdentifier: "NotificationCell") 9 tableView.estimatedRowHeight = 65 10 tableView.rowHeight = 65 11 tableView.delegate = self 12 tableView.dataSource = self 13 } 14 15 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 16 print("5") 17 //セルの読みこみ 18 let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationCell", for: indexPath) as! NotificationCell 19 //通知本文を表示 20 cell.message.text = notificationArray[indexPath.row]["message"]! 21 return cell 22 } 23 24 //お知らせを読み込む 25 func loadNotification() { 26 print("2") 27 //初期化 28 notificationArray = [[String:String]]() 29 //データベース参照 30 let ref = Database.database().reference(fromURL: "https://bookshare-b78b4.firebaseio.com/") 31 //データを取得 32 ref.child("Notification").child(userID).observe(.value) { (snap) in 33 for data in snap.children { 34 print("3") 35 let snapdata = data as! DataSnapshot 36 //辞書型に変換 37 let item = snapdata.value as! [String:String] 38 //配列に追加 39 self.notificationArray.append(item) 40 } 41 //tableViewを更新 42 self.tableView.reloadData() 43 } 44 print("4") 45 } 46

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

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

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

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

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

guest

回答1

0

ベストアンサー

これはFirebase Realtime Database を使い始めの方が一番初めにつまずくポイントです。

このポイントを押させてください。
Realtime Databaseでは直接値を参照することはできない
そんな馬鹿なと思われますが、実際できません。 これはそういうものなのであきらめてください。

ではどのように値を参照するかというと
0. 前回から値が更新されたときに呼び出される関数を登録する

  1. 前回から値が更新されると、その値(のコピー)を使って登録した関数が呼び出される。

という段階を経ることになります。

質問者さんのコードのprint("3")の部分は 1) に当たります。
ここでは関数の登録だけで、関数は呼び出されません。
ただし、登録直後にネットワーク上の状態が確認され、前回から値が更新されているため関数が呼び出されます。
(最初の呼び出しなので前回はデータがないときと判断されます)
確認には少し時間がかかるため、実行は遅延されます。

また、この関数呼び出しは値の更新があるたび何度でも呼び出されますので、質問者さんのコードですと、値が更新されるたびに、表示が重複されることになりますので気を付けてください。

投稿2019/02/05 05:04

MasakiHori

総合スコア3384

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

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

nekokichi

2019/02/05 08:10

とてもためになる回答をくださりありがとうございます。 お手数ですが、2つの質問にお答えいただきたいです。 ・上から順に実行されるような自然な処理順を実現するには、Dispatchqueueのような同期通信を使う必要があるのでしょうか? ・”質問者さんのコードですと、値が更新されるたびに、表示が重複されることになりますので気を付けてください。”についてですが、値が更新されるというのはデータベース参照先で値が更新されるということですか?  ・表示が重複させないためにできる対策はありますか? どうかよろしくお願いします。
MasakiHori

2019/02/05 08:49

あなたのいう「自然な処理順を実現する」ことに何の意味がありますか? 僕個人からすればこれが自然な処理順序です。 この場面でスレッドのブロックが必要ならそのアプリの設計が失敗しています。 どうしても上から順に動いて(いるように見えて)ほしいというのであれば、BrightFutures https://github.com/Thomvis/BrightFutures のようなFutureを使うことをお勧めします。
nekokichi

2019/02/06 03:35

ここまで付き合っていただきありがとうございます。 流石に処理の構造を根本から変えようなんて考えてた自分がバカでした。 今後はコードの流れをしっかり把握できるように努めてまいります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問