问题
I'm seeking to populate the tableview of my users with the last message they sent or were sent just like the initial View on Messages App on iphone. I have this code but it doesn't work to iterate through the array of dictionaries that I keep snapshots in of all the messages that were sent to the user and return the expected result:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
func getMsg()-> Int{
var getIndex = Int()
let messageDb = Database.database().reference().child("iMessenger/Messages")
messageDb.observe(.childAdded) { (snapshot) in
if let snapshotvalue = snapshot.value as? [String:Any], let sender = snapshotvalue["sender"] as? String, let key = snapshotvalue["key"] as? String{
// I thought that I could iterate through my array of dictionaries taking care to find a matching sender value for the user at indexpath.row and the key for the message
for (index, dict) in newMessageDictArr.enumerated(){
if self.users[indexPath.row].userPhone == sender && dict["key"] == key{getIndex = index}}}}
return getIndex}
if newMessageDictArr.count != 0{
cell.userMessage.text = newMessageDictArr[getMsg()]["messageBody"]}
return cell}
The problem I'm having with the code is that
cell.userMessage.text = newMessageDictArr[getMsg()]["messageBody"]
Makes all my cells have the first value for ["messageBody"] so it's like all my users seemed to have sent me the same message. Trying to figure out where I went wrong...
Also here's my FireBase structure, thanks.
{
"iMessenger" : {
"Messages" : {
"-KxDSQOBuCkpFdw4SPDh" : {
"messageBody" : "TEST ",
"receiver" : "+197862",
"sender" : "+16698"
},
"-KxBjNM_iA2XaapyyC9o" : {
"key" : "-KxBjNM_iA2XaapyyC9o",
"messageBody" : "TEST",
"receiver" : "+197862",
"sender" : "+1914862"
},
"Messages+199862+197862" : {
"-KxB7P-vgdfxRpSdnwCT" : {
"messageBody" : "yo, wassup world",
"receiver" : "+197862",
"sender" : "+199862"
},
"-KxB81fbn5_OHxdj4lcA" : {
"messageBody" : "Hello World",
"receiver" : "+19147862",
"sender" : "+1997862"
}
},
"Users" : {
"-Kx41o03NIMBR68F2sCS" : {
"displayName" : "sleeping beauty ",
"firstName" : "",
"lastName" : "",
"phoneNumber" : "+165698"
},
"-Kx42IXgN1z9D5Zoz0fk" : {
"displayName" : "KarmaDeli",
"firstName" : "",
"lastName" : "",
"phoneNumber" : "+1397862"
}}}}
回答1:
The question is a bit unclear but let me give it a shot:
Conceptually, a tableView is backed by an array of data. When that data changes the array should be updated, and then tableView.reloadData should be called to refresh what's in the tableView. In general, that technique provides the smoothest experience for the user.
IMO, the code should be rewritten to follow that design pattern. I'm not going to write all the code but will provide a flow and a couple of code snippets to give you some direction. These are not tested so don't copy and paste.
First, start with two classes
class MessageClass {
var msgId = ""
var msgBody = ""
var msgSenderUid = ""
var msgReceiverUid = ""
}
class UserClass {
var uid = ""
var name = ""
func init(aUid: String, aName: String) {
self.uid = aUid
self.name = aName
}
}
then two arrays to keep track of data - the first, messagesArray, will be the dataSource for your tableView
var messagesArray = [MessageClass]()
var usersArray = [UsersClass]()
We're going to assume the app has a couple hundred users so we're just going to load all of the user data in on app start. Keep in mind that if a new user is added, the usersArray will be updated with the additional user automatically
func viewDidLoad() {
let ref = firebaseRef.child("users")
ref.observe(.childAdded..... { snapshot in
let userDict = snapshot.value as! [String: Any]
let uid = userDict.key
let name = userDict["name"] as! String
let userClass = User(aUid: uid, aName: name)
self.usersArray.append(userClass)
and also add an observer to the messages node so your app will be notified of new messages. We are going to leverage a Firebase query observer so this user will only be notified of messages meant for them
let queryRef = firebaseRef.child("messages")
queryRef.queryOrdered(byChild: "msg_receiver_uid").query(equalTo: thisUsersUid) {
let dict = snapshot.value as! [String: Any]
let sendersUid = dict["msgSenderUid"] as! String
let msgText = dict["msgBody"] as! String
//create a MessageClass object and populate it with data
//add it to the messagesArray
tableView.reloadData()
then finally, in your tableView functions, get each row from the dataSource messagesArray and create and populate each cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
let msg = self.messagesArray[indexPath.row]
let msgSenderUid = msg.msgSenderUid
let sendersName = //some function to look up the senders name from the users array
let msg = msg.msgBody
//populate cell with users name and msg body
return cell
Again, this is not meant for copy/paste but to provide an example flow.
As new messages are posted, if the message is for this user, they will be notified of the message via the query observer and presented the message in an event. The messages is stuffed into a message class object, added to the datasource array and the tableview is updated to display it.
One caveaut to this is if you don't want to load all of the users. In that case, when a message event occurs, perform a observeSingleEvent on the users node to retreive the user info. Then within that closure, build the messageClass, add to array and reload the tableView.
Hope that helps.
来源:https://stackoverflow.com/questions/46915747/populate-tableviewcells-with-snapshot-values-in-swift