【问题标题】:Firebase: Retrieve information from nested Childs (Swift 3)Firebase:从嵌套的 Childs 中检索信息(Swift 3)
【发布时间】:2017-10-11 11:49:15
【问题描述】:

我有以下 Json 结构:

{
  "users" : {
    "yebl4egdQAcKyO7fRx3" : {
      "Calls" : {
        "Call_1" : {
          "CallNumber" : "1",
          "CallStatus" : "activ",
          "CallTitle" : "Test",
          "username" : "Kurt"
        },
        "Call_2" : {
          "CallNumber" : "2",
          "CallStatus" : "activ",
          "CallTitle" : "kfkf",
          "username" : "Kurt"
        },
      },
      "Country" : "USA",
      "Date of Birth" : "19770101",
      "Gender" : "M",
      "email" : "kurt@küde.com",
      "username" : "Kurt"
    }
  }
}

现在,我尝试检索以下数据:

1) 子“Calls”中的调用次数。我试图用这段代码做到这一点:

let databaseRef = FIRDatabase.database().reference()

        databaseRef.child("users").child("Calls").observe(.value, with: { snapshot in

            let CallCount = snapshot.childrenCount

            self.checkCall = Int(CallCount)

            print("check")
            print(self.checkCall)

        })

代码应该返回每个用户的调用次数。但是此代码返回零。似乎我没有正确解决我的观察,因为我的 Json 树是嵌套的。

2) 我需要取回所有用户的单个调用的整个字典(假设不只是示例中的一个):

    struct SingleCall {

        let callNumber: String!
        let callStatus: String!
        let callTitle : String!
        let username : String!
            }

 let databaseRef = FIRDatabase.database().reference()

        databaseRef.child("users").child("Calls").observe(.value, with: { snapshot in

            var newItems: [SingleCall] = []
            let enumerator = snapshot.children
            while let rest = enumerator.nextObject() as? FIRDataSnapshot {

                if self.Filter == (rest.value as? NSDictionary)!["Category"] as! String {

                    let callNumber        = (rest.value as? NSDictionary)!["CallNumber"] as! String

                    let callStatus        = (rest.value as? NSDictionary)!["CallStatus"] as! String

                    let callTitle        = (rest.value as? NSDictionary)!["CallTitle"] as! String

                    let username        = (rest.value as? NSDictionary)!["username"] as! String

                    newItems.append(SingleCall(callNumber: callNumber, callStatus: callStatus, callTitle: callTitle, username : username))

                }
            }
        })

这也不好用,因为我似乎没有正确地处理 Childs 来检索信息。我还在这里检查了几个条目,但无法帮助自己处理这些条目。我正在使用 Swift 3 进行编程,但我希望使用该语言提供解决方案。

【问题讨论】:

    标签: ios json swift firebase swift3


    【解决方案1】:

    因此,导致您没有接到任何电话的主要问题是您错过了此行 databaseRef.child("users").child("Calls") 上的子路径,即用户 uid。我已经使用上面的 JSON 对 Firebase 进行了测试,它可以工作。

    import UIKit
    import Firebase
    
    class TestTableViewController: UITableViewController {
    
        var users = Array<User>()
    
        var filtered = Array<User>()
    
        var filter = "active"
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let ref = FIRDatabase.database().reference().child("users")
    
            ref.observeSingleEvent(of: .value, with: { (snapshot) in
    
                guard let data = snapshot.value as? Dictionary<String,Dictionary<String,Any>> else { return }
    
                for (uid, value) in data {
    
                    if let user = User(uid: uid, dict: value) {
    
                        self.users.append(user)
    
                    } else {
    
                        print("Incomplete User Data.")
                    }
                }
    
                self.tableView.reloadData()
            })
        }
    
        func filterCalls(){
    
            self.filtered.removeAll()
    
            for user in users {
    
                let calls = user.calls.filter { $0.status == self.filter }
    
                var newUser = user
    
                newUser.calls = calls
    
                self.filtered.append(newUser)
            }
        }
    
        // MARK: - Table view data source
    
        override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    
            return self.users[section].username
        }
    
        override func numberOfSections(in tableView: UITableView) -> Int {
    
            return self.users.count
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
            if users.count > section {
    
                return self.users[section].calls.count
            }
    
            return 0
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    
            // Configure the cell...
    
            cell.textLabel?.text = self.users[indexPath.section].calls[indexPath.row].title
    
            cell.detailTextLabel?.text = self.users[indexPath.section].calls[indexPath.row].number
    
            return cell
        }
    }
    
    struct User {
    
        var uid: String
    
        var country: String
    
        var dob: String
    
        var gender: String
    
        var email: String
    
        var username: String
    
        var calls: Array<Call>
    
        init?(uid: String, dict: Dictionary<String,Any>) {
    
            guard
    
                let country = dict["Country"] as? String,
    
                let dob = dict["Date of Birth"] as? String,
    
                let gender = dict["Gender"] as? String,
    
                let email = dict["email"] as? String,
    
                let username = dict["username"] as? String,
    
                let calls = dict["Calls"] as? Dictionary<String,Dictionary<String,String>>
    
            else {
    
                return nil
            }
    
            self.uid = uid
    
            self.country = country
    
            self.dob = dob
    
            self.gender = gender
    
            self.email = email
    
            self.username = username
    
            self.calls = Array<Call>()
    
            for (_, value) in calls {
    
                guard let call = Call(dict: value) else { continue }
    
                self.calls.append(call)
            }
    
            self.calls.sort { $0.number < $1.number }
    
            self.calls = self.calls.filter { $0.status == "active" } // This will filter the array so only the active calls are there.
        }
    }
    
    struct Call {
    
        var number: String
    
        var status: String
    
        var title: String
    
        var username: String
    
        init?(dict: Dictionary<String,String>) {
    
            guard
    
                let number = dict["CallNumber"],
    
                let status = dict["CallStatus"],
    
                let title = dict["CallTitle"],
    
                let username = dict["username"]
    
            else {
    
                return nil
            }
    
            self.number = number
    
            self.status = status
    
            self.title = title
    
            self.username = username
        }
    }
    

    这将使表格视图看起来像这样。

    【讨论】:

    • 非常感谢,特里斯坦。抱歉,但我现在在使 Call 中的信息可用于 TableView 方面有点困难。在这方面你也能给我一些建议吗?谢谢
    • 最后一个问题:如果我知道只想过滤状态为活动的呼叫,我该怎么做?我理解你提出的概念,但我仍然难以实际处理。非常感谢您的帮助
    • 你可以使用类似的东西来过滤数组calls.filter { $0.status == "active" }。我已在 User init 方法中将其添加到上面的代码中。
    • 谢谢,知道了。如果过滤器来自 ViewDidLoad 中的 Var(字符串)怎么办(例如,当您有不同的类别来更改此 Var 时)。如果我尝试将过滤器设置为等于此 Var 它返回错误:不能使用实例成员
    • 我在上面添加了过滤功能。我真的不明白你想要它,但这可能会让你知道如何去做。
    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多