Firebase – iOS Swift:使用从两个单独的子节点中检索的数据加载表格视图单元格

我正在使用Firebase构build应用程序,以在表格视图中显示问题列表。 每个表视图单元格包含问题的文本,发布它的用户的名称以及发布该用户的个人资料照片。

下面是我如何构build我的JSON树:

"questions" "firebase_autoID_01" "name": "Jim" "text": "Why is the earth round?" "userID": "123456" "userInfo" "userID": "123456" "photoURL": "gs://default_photo" 

我试图检索每个问题的nametext ,用相应的userID用户的photoURL ,然后将这3个元素放在每个表视图单元格。 所以我试图从questions子节点和独立的userInfo子节点检索数据,把这些数据放到同一个表视图单元格。 这里是我一直试图做的代码:

当用户第一次创build时,我将他们的photoURL设置为手动上传到Firebase存储的默认图像:

 ... 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) } } 

当我尝试从questionsuserInfo检索数据时,问题就开始发生:

 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) } }) } }) } 

我在Xcode控制台中得到以下错误:

“终止应用程序,由于未捕获的exception'NSInternalInconsistencyException',原因:'无效的更新:在0节中的行数无效。更新(2)后,现有节中包含的行数必须等于包含在更新前的那个部分(0),加或减从该部分插入或删除的行数(插入1个,删除0个),加上或减去移入或移出该部分的行数(移入0,0搬出)。'”

我在这里做的是创build一个firebase句柄来观察/从userInfo子项中检索用户photoURL ,并且该句柄是在观察/从questionsphotoURL检索数据的句柄的闭包内部创build的。

问题 :如果这不是检索我想要的数据的正确方法,我应该如何处理? 而且,如果我的JSON数据目前没有正确的结构,应该如何构build?

下面是我如何parsing表视图中的questions子节点的nametext ,它工作正常:

 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! } 

问题 :我应该在这里还是在之前的configureDatabase()函数中解压缩photoURL

既然你问了关于如何在JSON中存储你的数据库结构的build议。 : –

build议的JSON结构: –

  {"Users" : { "userID_1" : { userName : "Jim", userImageURL : "gs://default_photo", questionsAsked : { "questionID_1" : "QUESTION TEXT", "questionID_2" : "QUESTION TEXT" } } "userID_2" : { userName : "Moriarty", userImageURL : "gs://default_photo", questionsAsked : { "questionID_1" : "QUESTION TEXT", "questionID_2" : "QUESTION TEXT" } } } } 

既然你打算显示发布问题的用户的图片和名称以及问题本身,我认为如果你在usersId本身中创build了questionAsked的孩子,那么最好的办法就是跟踪“否”和什么问题由特定的用户提出。

保存用户的个人资料数据将如下所示:

  FIRDatabase.database().reference().child("Users").child(FIRAuth.auth()!.currentUser()!.uid).setValue([ userName : "Jim", userImageUrl : //URL that you want to save ]) //Instead of FIRAuth.auth()!.currentUser()!.uid you can use childByAutoId too but i wont recommend that. 

当用户使用此代码进行职位调用时: –

  let rootRef = FIRDatabase.database().reference().child("Users").child(FIRAuth.auth()!.currentUser()!.uid).child("questionsAsked") rootRef.observeEventType(.Value, withBlock: {(snap) in if snap.exists(){ if let questionsDictionary = snap.value as? NSMutableDictionary{ questionsDictionary.setObject("Why is the earth round?", forKey: //your questionID) rootRef.setValue(questionsDictionary) } }else{ rootRef.setValue([ your_questionID : "Why is the earth round?" ]) } }) 

如何检索问题: –

  let parentRef = FIRDatabase.database().reference().child("Users") parentRef.observeEventType(.Value, withBlock: {(userSnap) in if userSnap.exists(){ for eachUser in userSnap.value as! [String:AnyObject]{ let userId = eachUser.key as! String parentRef.child(userId).observeEventType(.Value, withBlock: {(userSnap) in if let userInfo = userSnap.value as? [String:AnyObject]{ let userNameRecieved = userInfo["userName"] as! String let userImageUrlRecieved = userInfo["userImageURL"] as! String parentRef.child(userId).child("questionsAsked").observeEventType(.Value, withBlock: {(usersQuestion) in if userQuestion.exists(){ for eachQ in userQuestion.value as! [String:AnyObject]{ let question = eachQ.value as! String //Create a function named - "initialiseCell" , that will initialise the datasource of the tableView with username, photoURL and question as its : String parameters initialiseCell(question,userNameRecieved,userImageUrlRecieved) } } }) } }) } } }) 

至于你的问题ID: –

let yourQuestionID = "\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))

这会在下一秒或者毫秒时间内产生一个唯一的yourQuestionID

这个检索function在这个阶段,调用你的整个应用程序数据库中的每个问题,但你可以通过进一步修改代码来过滤它…

这就是我构buildFirebase JSON树的方式:

 "users": "userID4321": "displayName": "bob" "photoURL": "gs://default_photo" "questions": "questionID5678": "text": "How are you?" "userID": "userID4321" 

然后我在我的configureDatabase方法中实现了下面的代码:

 func configureDatabase() { ref = FIRDatabase.database().reference() _refHandle = self.ref.child("questions").observeEventType(.ChildAdded, withBlock: {[weak self] (questionSnapshot) in let questionID = questionSnapshot.key var question = questionSnapshot.value as! [String: AnyObject] question[Constants.QuestionFields.questionID] = questionID let userID = question[Constants.QuestionFields.userID] as! String let usersRef = self?.ref.child("users") usersRef?.child(userID).observeEventType(.Value, withBlock: { (userSnapshot) in var user = userSnapshot.value as! [String: AnyObject] let photoURL = user[Constants.UserFields.photoUrl] as! String let displayName = user[Constants.UserFields.displayName] as! String question[Constants.QuestionFields.photoUrl] = photoURL question[Constants.QuestionFields.displayName] = displayName ... 

questionsobserveEventType上的observeEventType句柄为每个问题对象添加一个快照,每次添加一个新的子observeEventType或者创build一个新的问题。 然后,我通过从Firebase服务器检索到的问题快照创build本地字典。 用这个问题的userID ,然后我可以用另一个observeEventType方法识别相应的用户,并检索该用户的photoURL并将其附加到问题快照。

一旦我需要的所有数据都在本地question词典中,我将它附加到我的questionsArray ,它被发送到表视图以显示每个问题与适当的数据。

让我知道如果有谁读这个会做不同的!