【问题标题】:How to compare answer of selected row and retrieve the answer from firebase?如何比较所选行的答案并从 Firebase 中检索答案?
【发布时间】:2017-02-25 07:51:34
【问题描述】:

我目前正在开发一款葡萄酒搜索器应用程序。基本上,我用食物搭配葡萄酒。用户选择他最喜欢的食物。我有我的 firebase 数据库存储带有特定葡萄酒名称和类型的葡萄酒数据。这是我在 firebase 中的 json 结构。

Wines:
  Wine1: 
   Name: Catena Zapata Malbec
   Type: Bold Red
  Wine2:
.......... etc.

我有另一个以前的视图控制器用于选择最喜欢的食物。例如,如果用户选择红肉,则相关输入将是“Bold Red”。 所以,我做了一个 switch case,对于 case:1(这是选择的红肉),参考进入“类型”并搜索“Bold Red”,最后打印出该红酒的所有相关结果。

class Wine: NSObject{
    var name: String?
    var type: String?
    var foodChoice: String?
}


class ResultViewController: UITableViewController {

var ref: FIRDatabaseReference!
var refHandle: UInt!
var wineList = [Wine]()
var intPassed: Int!
let cellId = "cellId"

override func viewDidLoad() {

    super.viewDidLoad()

    navigationItem.title = "Results" 
    ref = FIRDatabase.database().reference()
    fetchWine() 
}


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return wineList.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellId)
    cell.textLabel?.text = wineList[indexPath.row].name

    return cell
}


func fetchWine(){
    switch intPassed {
    case 0:
        refHandle = ref.child("Wines").observe(.childAdded, with: { (snapshot) in
            if let dictionary = snapshot.value as? [String: AnyObject] {
                let wine = Wine()
                wine.name = dictionary["name"] as! String?
                wine.type = dictionary["type"] as! String?

                wine.setValuesForKeys(dictionary)
                self.wineList.append(wine)

                print (wine.name, wine.type)

                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }
        })
    case 1:
        refHandle = ref.queryOrdered(byChild: "Type").queryEqual(toValue: "Bold Red").observe(.value, with: {(snapshot) in
            if let dictionary = snapshot.value as? [String: AnyObject] {
            let wine = Wine()
            wine.name = dictionary["name"] as! String?

            wine.setValuesForKeys(dictionary)
            self.wineList.append(wine)

            print (wine.name)

            DispatchQueue.main.async {
                self.tableView.reloadData()
            }

        }
    })
default:
        print("nothing")

    }
}  
}

我可以打印案例 0 的数据。但是如果我想将所选类型的答案与数据库中的类型进行比较,我无法获得我想要的数据。是不是 refHandle 的引用错了?

这是为案例 0 打印的结果。我只需要确保 firebase 正常工作。其他选项只是我数据库中的其他葡萄酒。

0
Optional("Catena Zapata Malbec") Optional("Bold Red")
Optional("Merlot") Optional("Medium Red")
Optional("Pinot Noir") Optional("Light Red")

请帮忙!非常感谢!!

【问题讨论】:

  • 您不需要在 fetchWine 函数中使用 intPassed(除非它是类定义的,否则它无论如何都是无效的,在这种情况下它将是 self.intPassed)。松开 DispatchQueue,因为它们不需要。

标签: swift firebase swift3 firebase-realtime-database


【解决方案1】:

问题

我观察到您的refHandle 似乎是正确的。但是您在观察块中访问数据错误。

解决方案

您的dictionary 情况 1 如下所示:

["Wine1": {
   name = "Catena Zapata Malbec";
   type = "Bold Red";
}]

这意味着,在这种情况下,您需要访问另一个字典才能仅访问您的葡萄酒的名称 Catena Zapata Malbec

case 1:
    refHandle = ref.queryOrdered(byChild: "Type").queryEqual(toValue: "Bold Red").observe(.value, with: {(snapshot) in
        if let dictionary = snapshot.value as? [String: AnyObject] {

          // Here access your name of the wine in the node
          if let wine1Dictionary = dictionary["Wine1"] as? [String: AnyObject] {
            let wine = Wine()
            wine.name = wine1Dictionary["name"] as! String?


            wine.setValuesForKeys(wine1Dictionary)
            self.wineList.append(wine)

            print(wine.name)
          }
    }
})

【讨论】:

  • 你试过运行你的代码吗?它以多种方式失败,因为它不能处理(很好)多个 Bold Red,它过于复杂,setValuesForKeys 在这个用例中是有问题的,并且不需要 DispatchQueue 调用。另外,这些都不需要refHandle,虽然不影响操作。
  • 测试了有关从 OP 访问具有给定结构的数据的代码。但是我没有用 switch 案例测试整个逻辑,refHandle 的使用,我也没有进一步考虑多个案例。没错,不需要 DispatchQueue 调用
  • 最大的问题是它没有解决问题打印出该红酒的所有相关结果。您的代码只处理一种特定的红酒,Wine1,等等重要的是,如果 Wine1 实际上是一个 childByAutoId() 键(它应该是),其中键节点事先不知道,它会失败。 OP 希望将加载到数组中的所有结果用作数据源,然后该数据源将用于向用户呈现数据库中与所选食物完美搭配的所有葡萄酒,而不仅仅是一种。您能否更新您的答案以解决 OP 的问题?
  • 我没有尝试运行多个“Bold Red”,我可能会尽快尝试!也谢谢老哥的回答!
【解决方案2】:

让我们用一个结构、检索特定类型葡萄酒的代码和一个想法来回答这个问题。

假设客户正在享用多肉或辛辣的晚餐,并且想要搭配一些葡萄酒选择。他们知道大胆的红色是要走的路

您的葡萄酒结构如下所示;请记住,应使用 childByAutoId() 生成父键

wines
  wine_id_0
    name: "Joseph Phelps Insignia"
    type: "Bold Red"
  wine_id_1
    name: "Heitz Cellers: Martha's Vineyard"
    type: "Bold Red"
  wine_id_2
    name: "Seasmoke Southing"
    type: "Fruity Red"

然后我们需要一个类或结构体,我们可以将其存储在一个数组中,该数组是我们 tableView 的数据源,然后是在我们加载葡萄酒时保存葡萄酒的数组。

struct WineStruct {
    var key = ""
    var name = ""
    var type = ""
}

var wineArray = [WineStruct]()

最后,一个冗长的代码 sn-p 读入(在这种情况下)所有的 Bold Red wines。

        let wineTypeToQuery = "Bold Red"
        let wineRef = ref.child("wines")
        let queryRef = wineRef.queryOrdered(byChild: "type")
                              .queryEqual(toValue: wineTypeToQuery)
        queryRef.observeSingleEvent(of: .value, with: { (snapshot) in

            for child in snapshot.children {
                let snap = child as! FIRDataSnapshot
                let wineDict = snap.value as! [String: Any]
                var wine = WineStruct()
                wine.name = wineDict["name"] as! String
                wine.type = wineDict["type"] as! String
                wine.key = snap.key
                self.wineArray.append(wine)
            }

            //here you would call tableView.reloadData()
            //do not use DispatchQueue!
            for wine in self.wineArray { //print the wines as a test
                let aWine = wine as! WineStruct
                let name = aWine.name
                let type = aWine.type
                print("\(name)  \(type)")
            }
        })

结果输出

Joseph Phelps Insignia  Bold Red
Heitz Cellers: Martha's Vineyard  Bold Red

此代码将处理加载所有 Bold Red wines 以及保存在每个 wine 子节点中的任何其他相关数据。上面的代码可以大大压缩(大约是行数的 1/2),但为了便于阅读,我把它写得很冗长。

一个想法:

您可能需要考虑不同的结构,因为不同的葡萄酒可以搭配不同的食物。

例如:

wines
  wine_id_0
    name: "Joseph Phelps Insignia"
    type: "Bold Red"
    pairs_with:
      steak: true
      ribs: true
  wine_id_1
    name: "Heitz Cellers: Martha's Vineyard"
    type: "Bold Red"
    pairs_with:
      steak: true
      pork: true
  wine_id_2
    name: "Seasmoke Southing"
    type: "Fruity Red"
    pairs_with:
      cheese: true
      fish: true
    aromatics:
      spicey: true

使用这种结构,我们不会假设客户知道 Bold Red 搭配牛排。他们可以选择“牛排”,我们通过这种方式缩小结果范围。

当然,您可以进一步优化搜索,因为与肋眼肉(脂肪含量高,确实需要更高的酒精度才能切开它)搭配得很好的葡萄酒可能与与菲力特搭配的葡萄酒不同.

我在最后一种酒中加入了芳香剂,因为这会进一步缩小搜索范围 - 如果用户订购的是清淡的鱼片,那通常需要霞多丽或长相思。但是,如果它以黑色(辛辣)风格呈现,那么黑比诺通常会成为赢家。

希望对您有所帮助!喜欢这个应用概念!

【讨论】:

  • 谢谢你这么详细的建议!!!这种结构真的很有帮助,因为我也在考虑为用户提供不同的食物。我还想出了另一种方法。我尝试在葡萄酒字典中搜索键和值,如果我得到值“Bold Red”,然后打印出特定葡萄酒的名称,它也可以工作!
  • 我也会尝试你的解决方案,这个想法真的很有帮助。谢谢和欢呼;)
  • @ManPingCheung 如果答案有帮助,请接受它,以便其他用户也能受益。 :-)
  • 嘿伙计,我认为您的代码应该可以工作,但我遇到了另一个错误。 [FirebaseDatabase] 使用未指定的索引。考虑将 /wines 的 ".indexOn": "type" 添加到您的安全规则中以获得更好的性能 我已经将数据库规则更改为:{ "rules": { ".read": true, ".write": true, " Wines":{ ".indexOn": "type" } } }
  • @ManPingCheung 这不是真正的严重错误,但应该在未来解决。请参阅This Question 的答案以及 Firebase 关于使用索引Index Your Data 的文档。如果有帮助,别忘了接受答案!
猜你喜欢
  • 2020-12-09
  • 1970-01-01
  • 2015-07-07
  • 2015-05-05
  • 2020-07-03
  • 1970-01-01
  • 2012-10-01
  • 2022-11-13
  • 2014-09-06
相关资源
最近更新 更多