Michael Eliot Michael Eliot - 1 month ago 13
Swift Question

Pulling Data From Firebase Issue

Novice programmer, currently working on an ios app using firebase as our backend. I'm trying to grab values from the firebase database to populate a TableView, but there are two issues. Firstly, it seems to ignore the ref.observeSingleEvent that I set up to try and retrieve the values, and while running the console ouputs:


2016-10-16 00:26:02.635: STOP!! Will reset deviceID from memory.

2016-10-16 00:26:02.635: Failed to fetch default token Error Domain=com.firebase.iid Code=6 "(null)"


similar to this issue. I'm fairly certain I've followed the Firebase documentation correctly for setup.

Important Part of Code within 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
}


JSON Database that is in firebase:

{
"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"
}
}


}

UPDATE

So changing the firebase database in any way (like adding a random value) causes it to work momentarily, but then after stopping the app for some time it stops working again, and continues to work and not work sporadically. I think it has to do with the choice of observeSingleEvent but I'm not sure.

Answer

In general: It's best practise to create a function for your download purposes and call the function instead of putting all the lines of code inside your cell declaration:

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
}

Also you should use observeEventType, to handle the case, that there might be data added to your Firebase during runtime and you want the data to be added to your 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
        }
    })
}

To your case: Also I assume that your App crashes because indexPath out of bounds. It's not best practise to download your Firebase data according to your indexPath within the population of the Cell. Since, as stated correctly by Jay, the download is async.

You have to download your desired data first and then populate a tableView according to your data like this:

You create an Array of Models (struct) or 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()
    }
}

Then you set numbersOfRowsInSection to myArray.count

And fill your tableView with:

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
}

This would be our struct in this example:

struct MyStuct {
    var name: String = ""
}

Our Array instantiated in the ViewController class:

let myArray: [MyStruct] = []

In this best practise scenario we would call our myFirebaseFunc func at the viewDidAppear func of our ViewController.