Problem with row insertion in a UITableView

青春壹個敷衍的年華 提交于 2020-01-25 07:58:06

问题


I've got a UIView with a UITableView that lists chats. When clicking on a specific conversation, I'm segueing modally to another UIView that again holds a UITableView that lists the individual messages of that chat - i.e. the chat details.

The ChatDetailViewController looks like this:

class ChatDetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var UserLogo: UIImageView!
    @IBOutlet weak var UserName: UILabel!
    @IBOutlet weak var MessageList: UITableView!
    @IBOutlet weak var MessageTextField: UITextField!
    @IBOutlet weak var SendButton: UIButton!

    var conversation: Int = 0
    let apiService = APIService()
    var conversationDetails = ConversationDetails ()
    var groupedMessages = [Date : [ChatMessage]]()
    var keys = [Date]()



    override func viewDidLoad() {
        super.viewDidLoad()

        self.UserName.text = ""
        self.MessageList.separatorStyle = .none
        self.MessageList.delegate = self
        self.MessageList.dataSource = self

        // self.SendButton.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)

        // load messages:
        self.apiService.getChatMessages(conversation: self.conversation, completion: {result in
            switch result {
            case .success(let conversationDetails):
                DispatchQueue.main.async {
                    self.conversationDetails = conversationDetails

                    // prepare header section:
                    let URLstring = self.conversationDetails.participants![0].profileimage
                    let imgURL = URL(string: URLstring ?? "www.foo.com") // TODO: insert placeholder image
                    self.UserLogo.sd_setImage(with: imgURL, placeholderImage: UIImage(named: "icon.turq.png"))
                    self.UserLogo.clipsToBounds = true
                    self.UserLogo.layer.cornerRadius = self.UserLogo.frame.size.width / 2
                    self.UserName.text = self.conversationDetails.participants![0].username

                    // group and sort messages:
                    let cal = Calendar.current
                    self.groupedMessages = Dictionary(grouping: self.conversationDetails.messages!, by: { cal.startOfDay(for: $0.tsp!) })
                    self.keys = self.groupedMessages.keys.sorted(by: { $0 < $1 })

                    // reload:
                    self.MessageList.reloadData()
                }
            case .failure(let error):
                print("An error occured \(error.localizedDescription)")
            }
        })

        ...

    }



    ...


    func numberOfSections(in tableView: UITableView) -> Int {
        return self.keys.count
    }



    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let label = customSectionHeaderLabel()
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd-MM-yyyy"
        label.text = dateFormatter.string(from: self.keys[section])

        let headingContainer = UIView()
        headingContainer.addSubview(label)
        label.centerXAnchor.constraint(equalTo: headingContainer.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: headingContainer.centerYAnchor).isActive = true
        return headingContainer
    }

... 


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.groupedMessages[keys[section]]!.count
    }



    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MessageViewCell", for: indexPath) as! ChatMessageViewCellController
        let tspSortedInGroup = self.groupedMessages[self.keys[indexPath.section]]!.sorted(by: { $0.tsp! < $1.tsp! })
        let chatMessage = tspSortedInGroup[indexPath.row]
        cell.ChatMessageText.text = chatMessage.message
        cell.isIncoming = self.isIncoming(message: chatMessage)
        return cell
    }



    func isIncoming(message: ChatMessage) -> Bool {
        return message.sender?.id != Globals.shared.user?.id
    }



    @IBAction func sendMessage(_ sender: Any) {
        print(self.MessageTextField.text)
        // create new ChatMessage object
        let now = Date()
        var newMessage = ChatMessage()
        newMessage.tsp = now
        newMessage.message = self.MessageTextField.text
        newMessage.sender = Globals.shared.user



        // call api to store sent message
        self.apiService.sendChatMessage(conversation: self.conversation, message: newMessage.message!, completion: {result in
            switch result {
            case .success(let stringResponse):
                DispatchQueue.main.async {
                    // append to grouped messages
                    self.groupedMessages[self.keys.last!]?.append(newMessage)
                    var path = IndexPath(row: self.groupedMessages[self.keys.last!]!.count-1, section: self.keys.count-1)
                    self.MessageList.beginUpdates()
                    self.MessageList.insertRows(at: [path], with: .fade)
                    self.MessageList.endUpdates()
                    self.MessageTextField.text = nil
                    self.MessageList.scrollToRow(at: path, at: .bottom, animated: true)
                }
            case .failure(let error):
                print("An error occured \(error.localizedDescription)")
            }
        })
    }

...   

}

Pretty much everything works as you would expect. When I'm launching the app, then click on the details of a specific chat, all messages load. When I'm then typing a message and hit send, it gets stored in the database and is shown on screen. Screen scrolls down. All perfect. I can repeat sending messages. All fine too.

When I'm then going back to the Chat overview (swiping down the modal) and go into a different chat, all is fine as well. Same behavior as above.

Problems start as soon as I go back to a previously opened chat. Screen loads and all looks healthy to start out with. But when I then type a message and hit send, it doesn't show the message that I just typed, but the last one from that chat - the one that was sent before I left the screen. Typing and sending a second message does the same - i.e. not shows the one just typed or the previous message, but the last one I sent before leaving the screen.

What makes this even more weird is the fact that the console output of within func sendMessage- i.e. print(self.MessageTextField.text) shows the correct text and when checking the database, the correct chat message was stored. Going out of the ChatDetails and back in reloads the screen and the correct messages are shown.

So I'm guessing it has something to do with how I'm appending the message to the UITableView once the api call returns

self.groupedMessages[self.keys.last!]?.append(newMessage)
                    var path = IndexPath(row: self.groupedMessages[self.keys.last!]!.count-1, section: self.keys.count-1)
                    self.MessageList.beginUpdates()
                    self.MessageList.insertRows(at: [path], with: .fade)
                    self.MessageList.endUpdates()
                    self.MessageTextField.text = nil
                    self.MessageList.scrollToRow(at: path, at: .bottom, animated: true)

But I can't figure out what exactly is causing the error.

来源:https://stackoverflow.com/questions/59865792/problem-with-row-insertion-in-a-uitableview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!