I'm building an app using Firebase that displays a list of Questions in a table view. Each table view cell holds the text of the question, the name of the user that posted it, and the profile photo of the user that posted it.
Here is how I've structured my JSON tree:
"questions"
"firebase_autoID_01"
"name": "Jim"
"text": "Why is the earth round?"
"userID": "123456"
"userInfo"
"userID": "123456"
"photoURL": "gs://default_photo"
I'm trying to retrieve the name
and text
for each question and the photoURL
of the user with the corresponding userID
to then place those 3 elements in each table view cell. So I'm trying to retrieve data from the questions
child node AND the separate userInfo
child node to put that data into the same table view cell. Here is the code I've been trying to do that with:
When a user first gets created, I set their photoURL
to a default image that I manually uploaded to Firebase Storage:
...
let placeholderPhotoRef = storageRef.child("Profile_avatar_placeholder_large.png")
let placeholderPhotoRefString = "gs://babble-8b668.appspot.com/" + placeholderPhotoRef.fullPath
//let placeholderPhotoRefURL = NSURL(string: placeholderPhotoRefString)
let data = [Constants.UserInfoFields.photoUrl: placeholderPhotoRefString]
self.createUserInfo(data)
}
func createUserInfo(data: [String: String]) {
configureDatabase()
let userInfoData = data
if let currentUserUID = FIRAuth.auth()?.currentUser?.uid{
self.ref.child("userInfo").child(currentUserUID).setValue(userInfoData)
}
}
Issues start occurring when I try to retrieve data from both the questions
and userInfo
:
var photoUrlArray = [String]()
func configureDatabase() {
ref = FIRDatabase.database().reference()
_refHandle = self.ref.child("questions").observeEventType(.ChildAdded, withBlock: {(snapshot) -> Void in
self.questionsArray.append(snapshot)
//unpack the userID from the "questions" child node to indicate which user to get the photoURL from in the "userInfo" child node
if let uid = snapshot.value?[Constants.QuestionFields.userUID] as? String {
self._photoURLrefHandle = self.ref.child("userInfo").child(uid).observeEventType(.ChildAdded, withBlock: {(snapshot) -> Void in
if let photoURL = snapshot.value as? String {
self.photoUrlArray.append(photoURL)
self.tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: self.questionsArray.count-1, inSection: 0)], withRowAnimation: .Automatic)
}
})
}
})
}
I get the following error in the Xcode console:
"Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'"
What I'm doing here is creating a firebase handle to observe/retrieve the users photoURL
from the userInfo
child, and that handle is created inside the closure of the handle that observes/retrieves the data from the questions
child.
Questions: If this is not the right way to retrieve the data I want, how should I approach this? And how should I structure my JSON data if it isn't currently structure the right way?
Here is how I'm unpacking the name
and text
from the questions
child node in the table view and it's working fine:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell! = self.tableView.dequeueReusableCellWithIdentifier("tableViewCell", forIndexPath: indexPath)
//unpack question from database
let questionSnapshot: FIRDataSnapshot! = self.questionsArray[indexPath.row]
var question = questionSnapshot.value as! Dictionary<String, String>
let name = question[Constants.QuestionFields.name] as String!
let text = question[Constants.QuestionFields.text] as String!
cell!.textLabel?.text = name + ": " + text
return cell!
}
Question: should I unpack the photoURL
here or in the previous configureDatabase()
function?