从Firebase问题中提取数据

时间:2016-10-16 07:42:19

标签: json swift firebase firebase-realtime-database

新手程序员,目前正在使用firebase作为我们的后端处理ios应用程序。我试图从firebase数据库中获取值来填充TableView,但有两个问题。首先,它似乎忽略了我设置为尝试检索值的ref.observeSingleEvent,并且在运行控制台输出时:

  

2016-10-16 00:26:02.635:停止!!将从内存中重置deviceID   2016-10-16 00:26:02.635:无法获取默认令牌Error Domain = com.firebase.iid Code = 6“(null)”

类似于this问题。我非常确定我已经正确地按照Firebase documentation进行设置。

CommitteesTableViewController中代码的重要部分:

// Sets each cell up with its committee title
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "committeeCell", for: indexPath) as! CommitteeTableViewCell
    let committee = cell.committeeLabel
    let sectionRef = FIRDatabase.database().reference(withPath: "Committee".child(String(indexPath.section))
    let committeeRef = sectionRef.child(String(indexPath.row))
    let currentRef = committeeRef.child(String(indexPath.row)).child("name")
    currentRef.observeSingleEvent(of: .value, with: { (snapshot) in
        committee?.text = snapshot.value as? String
    })
    return cell
}

firebase中的JSON数据库:

{
"Committee" : {
    "0" : {
        "0" : {
            "name" : "First Disarmament and International Security Committee",
            "Head Chair" : "Jessie Mao",
            "Vice Chairs" : "Himaja Jangle, Sita McGuire",
            "Topics" : "Congo: Resources in Conflict, Modern Warfare: Privatization of War"
        },
        "1" : {
            "name" : "UN Special,  Political And Decolonization Committee",
            "Head Chair" : "Trevor Dowds",
            "Vice Chairs" : "Lucia Zhang, Sarah Yue",
            "Topics" : "A Review of UN Peacekeeping Operations, Situation in Sudan and South Sudan"
        },
        "2" : {
            "name" : "UN 6th Legal Committee",
            "Head Chair" : "Benjy Malings",
            "Vice Chairs" : "Sherry Guo, Emma Lautanen",
            "Topics" : "Reform of the ICC/ICJ System, Reconsidering the Responsibility to Protect (R2P)"
        },
        "name" : "Bloc A"
    },
    "1" : {
        "0" : {
            "name" : "UN Human Rights Council",
            "Head Chair" : "Amanda Lee",
            "Vice Chairs" : "Jessica Zhao",
            "Topics" : "Palestinian Women's Rights, Capital Punishment and the Rights of Prisoners"
        },
        "1" : {
            "name" : "UN Educational, Scientific, And Cultural Organization",
            "Head Chair" : "Adam Umemoto",
            "Vice Chairs" : "Emily Yan, Jacob Hands",
            "Topics" : "Child Soldiers: The Rights of Children in Armed Conflict, Reconsidering the 2030 Education Agenda"
        },
        "2" : {
            "name" : "UN Economic And Social Council",
            "Head Chair" : "Alex Feibleman",
            "Vice Chairs" : "Octavio Garcia Farfan, Liam Campbell",
            "Topics" : "Strengthening Resilience to Climate Related Disasters, Commercial Bribery in Multinational Organizations"
        },
        "3" : {
            "name" : "World Health Organization",
            "Head Chair" : "Mekhala Hoskote",
            "Vice Chairs" : "Brandon Doan, Ashley Njoroge",
            "Topics" : "Sustainable Vaccine Practices and Financing, Improving Slum Health"
        },
        "4" : {
            "name" : "International Criminal Police Organization, INTERPOL ",
            "Head Chair" : "Natasha Cougoule",
            "Vice Chairs" : "Chelsea Evans, Jacky Tian",
            "Topics" : "Controlling the Black Market Trade of Civil War Antiques, Protection of Journalists in Conflict Zones"
        },
        "name" : "Bloc B"
    },
    "2" : {
        "0" : {
            "name" : "UN Security Council",
            "Head Chair" : "Kim Nguyen, TJ Ford",
            "Vice Chairs" : "Mischa Fritz",
            "Topics" : "South China Sea, Open Agenda"
        },
        "1" : {
            "name" : "Historical UN Security Council",
            "Head Chair" : "Pranay Patil",
            "Vice Chairs" : "Michael Pollack",
            "Topics" : "Gulf War, Khmer Rouge"
        },
        "2" : {
            "name" : "North Atlantic Treaty Organization",
            "Head Chair" : "Gloria Cheung",
            "Vice Chairs" : "Trent Gomberg",
            "Topics" : "Post-Intervention Stability in Libya, Unrest in the East: Security in the Black Sea and Baltic Region"
        },
        "3" : {
            "name" : "African Union",
            "Head Chair" : "Itago Kangashi",
            "Vice Chairs" : "Zoe Brouns",
            "Topics" : "Volatile Political Systems: The Role of the AU in Establishing Democracies, The State of Agriculture and Food Security"
        },
        "4" : {
            "name" : "Organization Of American States",
            "Head Chair" : "Adrian Hernandez",
            "Vice Chairs" : "Jane Kim",
            "Topics" : "Drugs and Development in Latin America, Migration Movements in Latin America"
        },
        "5" : {
            "name" : "Chinese State Council",
            "Head Chair" : "Rita Hu",
            "Vice Chairs" : "Haochen Zhou",
            "Topics" : "Review on the Loosening of the One-Child Policy, One Belt, One Road"
        },
        "6" : {
            "name" : "United States Senate",
            "Head Chair" : "Jonas Majewski",
            "Vice Chairs" : "Eric Cherwin",
            "Topics" : "Immigration Reform and a Pathway to Citizenship, Trade Agreements and the American Economy"
        },
        "7" : {
            "name" : "UNEP Division Of Environmental Laws And Conventions",
            "Head Chair" : "Nate Parke",
            "Vice Chairs" : "Kendra Singh",
            "Topics" : "Compensatory Mitigation in a Global Context, Common but Differentiated Environmental Responsibility"
        },
        "8" : {
            "name" : "UN Framework Convention On Climate Change  - Conference Of The Parties 22.5",
            "Head Chair" : "Katie Lee",
            "Vice Chairs" : "Se Yeon Kim",
            "Topics" : "Building Adaptation Capacity for Vulnerable Communities, Governance of Geoengineering"
        },
        "9" : {
            "name" : "European Court Of Human Rights",
            "Head Chair" : "Jake Moskowitz",
            "Vice Chairs" : "Patty Midy",
            "Topics" : "Cyprus v. Turkey"
        },
        "10" : {
            "name" : "Press Corps",
            "Head Chair" : "Sarah Bauer",
            "Vice Chairs" : "Hyunwook Kim, Stacey Dojiri",
            "Topics" : "Open Agenda"
        },
        "name" : "Specialized"
    },
    "3" : {
        "0" : {
            "name" : "Joint Cabinet Crisis",
            "Head Chair" : "Michael Eliot",
            "Vice Chairs" : "Andy Luo, Michael McDonald, Tushita Saraf",
            "Topics" : "Trade Wars: Anglo-Dutch East India Companies"
        },
        "1" : {
            "name" : "Committee For Sustainable Development",
            "Head Chair" : "Rob Purviance",
            "Vice Chairs" : "Daksh Bhatia",
            "Topics" : "Rebuilding a Nation: Infrastructure Development in Myanmar"
        },
        "2" : {
            "name" : "Historical Crisis",
            "Head Chair" : "Arjun Banerjee",
            "Vice Chairs" : "Alex Wilfert",
            "Topics" : "Unification of Germany"
        },
        "name" : "Crisis"
    }
}

}

更新

因此,以任何方式更改firebase数据库(例如添加随机值)会使其暂时工作,但是在停止应用程序一段时间后它会再次停止工作,并继续工作而不是偶尔工作。我认为这与observeSingleEvent的选择有关,但我不确定。

3 个答案:

答案 0 :(得分:2)

您可以尝试更改此内容:

$ ./test.sh 1
test_string
$ ./test.sh 1
test_string
$ cat somefile
test_string
test_string
$ ./test.sh 0
test_string
$ cat somefile
test_string
test_string

到此:

let sectionRef = FIRDatabase.database().reference().child(String(indexPath.section))

答案 1 :(得分:1)

一般:为您的下载目的创建函数并调用函数而不是将所有代码行放在单元格声明中,这是最佳做法:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "committeeCell", for: indexPath) as! CommitteeTableViewCell

    // we are passing the Label and the indexPath to out func
    myFirebaseFunc(label: cell.committeeLabel, indexPath: indexPath)
    return cell
}

此外,您应该使用observeEventType来处理此案例,在运行时可能会有数据添加到您的Firebase,并且您希望将数据添加到UITableView

func myFirebaseFunc(label: UILabel, indexPath: NSIndexPath) {

    let sectionRef = FIRDatabase.database().reference(withPath: "Committee".child(String(indexPath.section))
    let committeeRef = sectionRef.child(String(indexPath.row))
    let currentRef = committeeRef.child(String(indexPath.row)).child("name")
    currentRef.observeEventType(of: .value, withBlock: { (snapshot) in

        if snapshot.exists() {
            label?.text = snapshot.value as? String
        }
    })
}

根据您的情况:另外,我认为您的应用程序崩溃是因为indexPath out of bounds。根据您在单元格群体中的indexPath下载Firebase数据并非最佳做法。因为正如 Jay 正确陈述的那样,下载是异步的。

您必须先下载所需的数据,然后根据您的数据填充tableView

您可以创建一个模型数组(struct)或NSMutableDictionary。

// first you check, if your snapshot exists
if snapshot.exists() {

    // you delete your Array, you your data will not be added multiple
    // times once you add data in the background and the func gets
    // called again

    self.myArray.removeAll()

    // you sort your snapshot according to your needs (for example of the (pre set) date value. If date is missing, the code will not crash!
    let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)])

    // then you loop through your sorted Array
    for element in sorted {

       // you create a name String of your name element in your Dictionary
       let name = element.valueForKey("name")! as? String

       // if you have created a struct, you instantiate a model and set the name
       let m = MyStruct(name: name!)

       // and you append it to your Array     
       self.myArray.append(m)      
    }
    // last but not least we reload our tableView on the main threat
    DispatchQueue.main.async{
        self.tableView.reloadData()
    }
}

然后将numbersOfRowsInSection设置为myArray.count

用表格填充你的tableView:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "committeeCell", for: indexPath) as! CommitteeTableViewCell

    let mine = myArray[indexPath.row]
    cell.committeeLabel.text = mine.name
    return cell
}

这是我们在这个例子中的结构:

struct MyStuct {
    var name: String = ""
}

我们的Array在ViewController类中实例化:

let myArray: [MyStruct] = []

在这个最佳实践场景中,我们将在ViewController的myFirebaseFunc函数中调用viewDidAppear func。

答案 2 :(得分:1)

Firebase是异步的:通过查询或观察调用从Firebase返回值需要一些时间。

你的代码是不允许的,所以发生的事情是调用observeSingleEvent并且在Firebase有机会返回数据并填充委员会之前,cellForRowAt函数返回(空)单元格。

代码比互联网快,因此您需要对观察区块(闭包)内的数据进行操作,因为它是有效的时间。

最佳做法是在Firebase观察块(闭包)中填充数据源 - 以下是步骤

  1. 通过观察.value块
  2. 从Firebase获取值
  3. 在块中,迭代返回的值并填充数组(数据源)
  4. 重新加载tableView
  5. 并按Head Char排序,这是一个很好的解决方案。假设dict中填充了来自Firebase的.values

    let dict = ["0": ["name": "First Disarmament and International Security Committee",
                  "Head Chair": "Jessie Mao"],
                "1": ["name": "UN Special,  Political And Decolonization Committee",
                  "Head Chair": "Trevor Dowds"],
                "2": ["name": "UN 6th Legal Committee",
                  "Head Chair": "Benjy Malings"]
    ]
    let sortedArray = Array(dict).sorted { $0.1["Head Chair"]! < $1.1["Head Chair"]! }