问题
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