Проблема со вставкой строки в UITableView - PullRequest
0 голосов
/ 22 января 2020

У меня есть UIView с UITableView, который перечисляет чаты. При нажатии на указанный c разговор, я модально перехожу к другому UIView, который снова содержит UITableView, в котором перечислены отдельные сообщения этого чата - т.е. детали чата.

ChatDetailViewController выглядит следующим образом:

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)")
            }
        })
    }

...   

}

Практически все работает, как и следовало ожидать. Когда я запускаю приложение, затем нажимаю на детали чата c, все сообщения загружаются. Когда я набираю сообщение и нажимаю кнопку отправить, оно сохраняется в базе данных и отображается на экране. Экран прокручивается вниз. Все идеально. Я могу повторить отправку сообщений. Все тоже хорошо.

Когда я возвращаюсь к обзору чата (пролистывая модальное) и go в другой чат, все тоже хорошо. То же поведение, что и выше.

Проблемы начинаются, как только я go возвращаюсь в ранее открытый чат. Экран загружается и все выглядит здоровым для начала. Но когда я набираю сообщение и нажимаю «Отправить», оно показывает не только что набранное сообщение, а последнее из этого чата - то, которое было отправлено до того, как я покинул экран. Ввод и отправка второго сообщения делает то же самое - то есть показывает не только что набранное или предыдущее сообщение, но и последнее, которое я отправил перед тем, как покинуть экран.

Что делает это еще более странным, так это тот факт, что вывод консоли в пределах func sendMessage - т.е. print(self.MessageTextField.text) показывает правильный текст, и при проверке базы данных было сохранено правильное сообщение чата. Выход из ChatDetails и возврат к перезагрузке экрана, и отображаются правильные сообщения.

Так что я предполагаю, что это как-то связано с тем, как я добавляю сообщение в UITableView, как только возвращается вызов API.

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)

Но я не могу понять, что именно является причиной ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...