Reputation: 8691
In my chat feature, I show to the current user his chats with other users in a tableview. Each cell on the tableview is the info, avatar and name, of the opposite user. It's easy to store these info in a chat object, but the problem is that the opposite user could have changed his avatar or name at that point.
Hence, I'm fetching the opposite user's avatar and name in the cell configuration of the chat. It's working fine but I'm not sure if there is a better way since I'm not sold on making Firebase network call in each cell.
Here is my cell configuration method:
func configureCell(from chat: Chat){
// 1st Get opposite user id
if let currentUser = Auth.auth().currentUser{
let user1 = chat.people.first
let user2 = chat.people.last
let user1Id = user1?["id"] ?? ""
let user2Id = user2?["id"] ?? ""
var oppositeUserId = ""
if user1Id == currentUser.uid{
oppositeUserId = user2Id
}else{
oppositeUserId = user1Id
}
//2nd Fetch opposite user doc
let oppositeUserDocRef = References.Instance.getUserDocRef(for: oppositeUserId)
oppositeUserDocRef.getDocument { (oppositeUserDocSnapshot, error) in
if error != nil{
print("ERROR FETCHING OPPOSITE USER DOC:: ERROR IS: \(error?.localizedDescription ?? "")")
return
}
// 3rd get opposite user avatar url and name
if let otherUserDic = oppositeUserDocSnapshot?.data(){
if let avatarDic = otherUserDic["avatar"] as? [String: String]{
let avatarUrl = avatarDic["url"] ?? ""
self.avatarView.sd_setImage(with: URL(string: avatarUrl),
placeholderImage: nil, options: .refreshCached)
}
if let name = otherUserDic["name"] as? String{
self.uiLabelChatTitle.text = name
}
}
}
}
}
Upvotes: 0
Views: 118
Reputation: 8691
As they suggested in the comments, prefetching the data would be a better solution. It's tricky and depends on each app's details. My goal was to mimic WhatsApp's chat list functionality updating users info in realtime.
Here is what I did to achieve this:
func showChats(){
guard let currentUser = Auth.auth().currentUser else{
return
}
let profileController = UserProfileController.instance
if let snapshot = profileController.chats{
for document in snapshot.documents{
let chat = ChatController.instance.getChat(from: document)
chats.append(chat)
print("GOT CHAT:::: \(document.data())")
}
tableview.reloadData()
}
else{
print("NOTHING IN INBOX!!!!")
}
// Attach listeners to chat users docs to listen for change in avatars and names
// 1st: Loop through each chat to get people and know opposite user id
for (i, var chat) in chats.enumerated(){
let person1 = chat.people.first
let person2 = chat.people.last
let person1Id = person1?["id"] ?? ""
let person2Id = person2?["id"] ?? ""
var oppositeUserId = ""
var opposteUsrIsPerson1 = false
if person1Id == currentUser.uid{
oppositeUserId = person2Id
opposteUsrIsPerson1 = false
}
else{
oppositeUserId = person1Id
opposteUsrIsPerson1 = true
}
// 2nd: Fetch opposite user doc and add listener to it
let oppositeUserDocRef = References.Instance.getUserDocRef(for: oppositeUserId)
let docListener = oppositeUserDocRef.addSnapshotListener { (oppositeUserDocSnapshot, error) in
if error != nil {
print("ERROR FETCHING OTHER PERSON DOC:: ERROR IS: \(error?.localizedDescription ?? "")")
return
}
// 3rd: get other user avatar url and name from his doc
if let oppositeUserDic = oppositeUserDocSnapshot?.data(){
var avatarUrl = ""
var name = ""
if let avatarDic = oppositeUserDic["avatar"] as? [String: String]{
avatarUrl = avatarDic["url"] ?? ""
}
if let oppositeUsrName = oppositeUserDic["name"] as? String{
name = oppositeUsrName
}
// 4th: Create ChatPerson object with the fetched values and replace the existing one
let chatPerson = ChatPerson(id: oppositeUserId, name: name, avatarUrl: avatarUrl)
if opposteUsrIsPerson1{
chat.people[0] = chatPerson.toDictionalry()
}
else{
chat.people[1] = chatPerson.toDictionalry()
}
// 5th: Update data and reload the chat row
self.chats[i] = chat
let indexpath = IndexPath(row: i, section: 0)
self.tableview.reloadRows(at: [indexpath], with: .automatic)
}
}
//6th: Add doc listener to liteners list to remove it later in deinit()
chatUserListeners.append(docListener)
}
}
In the view controller's deinit() loop through the listeners to remove them:
deinit {
for listener in chatUserListeners{
listener.remove()
}
}
Upvotes: 0
Reputation: 339
I have never really used Firebase but for something like this, I would say populate an array of 'chatDetails' objects in a single network request and then configure each reusable cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let chat = self.chatDetails[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier") as! ChatDetailsCell
cell.configureCell(chat: chat)
return cell
}
Upvotes: 1