olle
olle

Reputation: 154

Swift tableView Cells disappears on scroll

Trying to add a chat function in my app with tableView but whenever i scroll my chats some cells disappear and i am not sure why. Any help is appreciated.

The tableView is connected to dataSource and delegate in the storyboard.

I have created the cell itself in a xib file and depending on if it is a sender message or received message the cell will display different. This is the code for each cell:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "customMessageCell", for: indexPath) as! CustomMessageCell

    //Sets cell to message

    senderId = messageArray[indexPath.row].fromId

    if senderId == Auth.auth().currentUser?.uid as String? {
        //Messages We Sent 
        cell.ourMessageBody.text = messageArray[indexPath.row].messageBody

        cell.ourMessageBackground.backgroundColor = UIColor(displayP3Red: 59/255.0, green: 89/255.0, blue: 152/255.0, alpha: 1)
        cell.ourMessageBody.textColor = UIColor.white

        cell.avatarImageView.isHidden = true
        cell.messageBackground.isHidden = true

    } else{
        //Messages someone else sent
        cell.messageBody.text = messageArray[indexPath.row].messageBody
        cell.avatarImageView.backgroundColor = UIColor(white: 0.95, alpha: 1)
        cell.messageBackground.backgroundColor = UIColor(white: 0.95, alpha: 1)
        cell.ourMessageBackground.isHidden = true
        //toId ProfileImage
        if let imageID = toId{
            print(imageID)
            let imagesStorageRef = Storage.storage().reference().child("profilepic/").child(imageID)
            imagesStorageRef.getData(maxSize: 1*1024*1024, completion: { (data, error) in
                if error != nil{
                    print(error)
                    return
                }
                DispatchQueue.main.async {
                    cell.avatarImageView?.image = UIImage(data: data!)
                }

            })

        }
    }

    return cell
}

And here is the method for retrieving messages:

    func retrieveMessages() {

    let testUserOrAd = SwipingView.myAdvertiserVar.advertiser
    print("testing result: \(testUserOrAd) your are a User")

    //if advertiser
    if testUserOrAd == true{
        if let testId = self.toId{
            let MessageDB = Database.database().reference().child("Users").child(toId!).child("Messages").child(uid!)

            MessageDB.observe(.childAdded) { (snapshot) in
                let snapshotValue =  snapshot.value as! Dictionary<String,String>

                let text = snapshotValue["MessageBody"]!
                let fromId = snapshotValue["FromId"]

                let message = Message()
                message.messageBody = text
                message.fromId = fromId

                self.messageArray.append(message)

                self.configureTableView()
                self.messageTableView.reloadData()
            }
        }

    }else{
        //if user

        let MessageDB = Database.database().reference().child("Users").child(uid!).child("Messages").child(toId!)

        MessageDB.observe(.childAdded) { (snapshot) in
            let snapshotValue =  snapshot.value as? [String: AnyObject]

            let text = snapshotValue!["MessageBody"] as? String
            let fromId = snapshotValue!["FromId"] as? String

            let message = Message()
            message.messageBody = text
            message.fromId = fromId

            self.messageArray.append(message)

            self.configureTableView()
            self.messageTableView.reloadData()
        }

    }
}

And this is the result:

enter image description here

Upvotes: 0

Views: 2798

Answers (1)

Yannick Loriot
Yannick Loriot

Reputation: 7136

Your code is wrong because you configure your cells once (in the tableView:cellForRowAt: method) but when you scroll the table view if the user alternates, the avatarImageView, messageBackground and the ourMessageBackground will be all hidden eventually.

Try to update your code like that:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "customMessageCell", for: indexPath)

  cell.ourMessageBackground.backgroundColor = UIColor(displayP3Red: 59/255.0, green: 89/255.0, blue: 152/255.0, alpha: 1)
  cell.ourMessageBody.textColor = UIColor.white
  cell.avatarImageView.backgroundColor = UIColor(white: 0.95, alpha: 1)
  cell.messageBackground.backgroundColor = UIColor(white: 0.95, alpha: 1)

  self.tableView(tableView, willDisplay: cell, forRowAt: indexPath)

  return cell
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
  guard let cell = cell as? CustomMessageCell else { return }

  //Sets cell to message

  let senderId = messageArray[indexPath.row].fromId

  if senderId == Auth.auth().currentUser?.uid as String? {
    //Messages We Sent
    cell.ourMessageBody.text = messageArray[indexPath.row].messageBody

    cell.avatarImageView.isHidden = true
    cell.messageBackground.isHidden = true
    cell.ourMessageBackground.isHidden = false
  } else {
    //Messages someone else sent
    cell.messageBody.text = messageArray[indexPath.row].messageBody

    cell.avatarImageView.isHidden = false
    cell.messageBackground.isHidden = false
    cell.ourMessageBackground.isHidden = true

    //toId ProfileImage
    if let imageID = toId {
      let imagesStorageRef = Storage.storage().reference().child("profilepic/").child(imageID)
      imagesStorageRef.getData(maxSize: 1*1024*1024, completion: { (data, error) in
        if error != nil{
          print(error)
          return
        }

        DispatchQueue.main.async {
          guard let c = tableView.cellForRow(at: indexPath) else { return }

          c.avatarImageView?.image = UIImage(data: data!)
        }

      })

    }
  }
}

Furthermore as the avatar fetching is made in background, the cell may have changed when the data is retrieved. So you have to be sure the cell is still displayed. And you should cache the avatar to avoid to fetch it every time.

Upvotes: 2

Related Questions