私のデータ構造は、次のようなものです:Firebaseからデータを取得し、それを使用して
restaurant_owners
|
|owner_id (a unique ID)
|
|restaurant_name
|email
restaurant_menus
|
|restaurant_name
|
|dish_type (drinks, appetizer, etc...)
|
|dish_id (a unique ID)
|
|name
|
|price
アプリのアイデアは「restaurant_ownersは」のメニューにログインし、管理できるように、基本的ですそれぞれのレストラン。しかし、私は次のコードで問題を抱えています:
func fetchDish() {
var restaurantName: String?
let uid = FIRAuth.auth()?.currentUser?.uid
//first time referencing database
FIRDatabase.database().reference().child("owners").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
DispatchQueue.main.async{
restaurantName = dictionary["name"] as? String
print(restaurantName!)
}
}
})
//second time referencing database
FIRDatabase.database().reference().child("restaurants").child(restaurantName!).child("appetizer").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let dish = Dish()
dish.setValuesForKeys(dictionary)
self.dishes.append(dish)
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
}, withCancel: nil)
}
私は何をしようとしていますが現在ログインしているユーザーのためのレストランの名前を取得することです(fetchDish関数がのviewDidLoadで呼び出されることに注意してください)とそれを変数 "restaurantName"に格納します。その後、私が2回目にデータベースを参照しているときに、この変数を.childの内部で使用することができます(例:.child(レストラン名))。
しかし、これを実行すると、(データベース参照内の)restaurantNameの値がnilであるというエラーが表示されます。いくつかのブレークポイントを入れようとしましたが、第2のデータベース参照の最初の行が最初のデータベース参照の "内側"になる前に操作されているようです。
これはなぜ発生しますか?この問題を回避するにはどうすればよいですか?また、私が完全に間違っている場合、これを達成するためのベストプラクティスは何ですか?
NoSQLは私にとって非常に新しく、私は自分のデータ構造をどのように設計すべきか全くわかりません。事前にお手数をおかけしていただき、他の情報が必要な場合はお知らせください。
UPDATE:
問題はジェイが提案したものに私のデータ構造を変更することで解決しました。次のコードは、私のために働いているもの:(ジェイのコードビットを変更)
func fetchOwner() {
let uid = FIRAuth.auth()?.currentUser?.uid
let ownersRef = FIRDatabase.database().reference().child("owners")
ownersRef.child(uid!).observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? [String: AnyObject] {
let restaurantID = dict["restaurantID"] as! String
self.fetchRestaurant(restaurantID: restaurantID)
}
}, withCancel: nil)
}
func fetchRestaurant(restaurantID: String) {
let restaurantsRef = FIRDatabase.database().reference().child("restaurants")
restaurantsRef.child(restaurantID).child("menu").observe(.childAdded, with: { snapshot in
if let dictionary = snapshot.value as? [String: AnyObject] {
let dish = Dish()
dish.setValuesForKeys(dictionary)
self.dishes.append(dish)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
をDispatchQueue.mainを削除してください.async。それは必要ではありません。 – Jay
DispatchQueue.main.asyncを使用した場合に特に悪影響はありませんか? self.tableview.reloadData()を入れると、テーブルが情報をロードする時間が大幅に短縮されます。 – JustTro11
このアプリケーションでは、Firebaseデータがサーバから受信され、クロージャのコードが処理されるまで、tableViewがリフレッシュされないため、パフォーマンスに顕著な違いはありません。この場合、メインのシリアル・キューに非同期タスクが投げられています。このタスクでは、タスクがその前にあるものの背後に順番に配置されます。 Firebase機能は既に非同期であるため、不要です。 – Jay