使用MessageKit和Firestore插入消息时断言失败

时间:2019-03-15 22:07:06

标签: swift uicollectionview google-cloud-firestore messagekit

在我的MessagingViewController类上,每当我尝试从后端(Firestore)提取消息时,都会出现此错误:

enter image description here

我发现查询发生后collectionView不能更新,因此我在viewDidLoad()方法中添加了“ messagesCollectionView.reloadData()”。

没用。因此,之后,我在插入新消息的函数中添加了同一行:

private func insertNewMessage(_ message: Message) {
    guard !messages.contains(message) else { return }

    messages.append(message)
    messages.sort()
    messagesCollectionView.reloadData()

    messagesCollectionView.performBatchUpdates({
        messagesCollectionView.insertSections([messages.count - 1])
        if messages.count >= 2 {
            messagesCollectionView.reloadSections([messages.count - 2])
        }
    }, completion: { [weak self] _ in
        if self?.isLastSectionVisible() == true {
            self?.messagesCollectionView.scrollToBottom(animated: true)
        }
    })
}

仍然没有运气。如何正确加载查询中的消息并将其显示在collectionView上?是什么导致此错误?

其余代码如下:

final class MessageKitLogViewController: MessagesViewController, MessageInputBarDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

private let user: User
private var currentUser: User
private var messages: [Message] = []
private let db = Firestore.firestore()
private var reference: CollectionReference?
private var partnerReference: CollectionReference?
private var messageListener: ListenerRegistration?
private let storage = Storage.storage().reference()

let formatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    return formatter
}()

init(user: User, currentUser: User) {
    self.user = user
    self.currentUser = currentUser
    super.init(nibName: nil, bundle: nil)

    title = user.name
}


deinit {
    messageListener?.remove()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


override func viewDidLoad() {
    super.viewDidLoad()

    guard let userID = Auth.auth().currentUser?.uid, let partnerID = self.user.id else { return }

    reference = db.collection(["messages", userID, partnerID].joined(separator: "/"))
    partnerReference = db.collection(["messages", partnerID, userID].joined(separator: "/"))

    messageListener = reference?.addSnapshotListener { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error listening for channel updates: \(error?.localizedDescription ?? "No error")")
            return
        }

        snapshot.documentChanges.forEach { change in
            self.handleDocumentChange(change)
        }
    }

    if #available(iOS 11.0, *) {
        navigationItem.largeTitleDisplayMode = .never
    } else {}

    messageInputBar.delegate = self
    messageInputBar.inputTextView.tintColor = Colors.indexedGray
    messageInputBar.sendButton.tintColor = Colors.indexedGray
    messagesCollectionView.messagesDataSource = self
    messagesCollectionView.messagesLayoutDelegate = self
    messagesCollectionView.messagesDisplayDelegate = self
    scrollsToBottomOnKeyboardBeginsEditing = true // default false
    maintainPositionOnKeyboardFrameChanged = true // default false

    // InputTextView
    messageInputBar.inputTextView.layer.borderWidth = 0
    messageInputBar.inputTextView.backgroundColor = .white
    messageInputBar.inputTextView.font = UIFont.systemFont(ofSize: 16, weight: .regular)
    messageInputBar.inputTextView.placeholderTextColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 0.75)
    // - LayoutMargin
    messageInputBar.inputTextView.placeholderLabelInsets.left = 10

    // Send Button
    messageInputBar.sendButton.configure {
        $0.title = "Send"
        $0.setSize(CGSize(width: 55, height: 30), animated: true)
        $0.backgroundColor = Colors.indexedGray
        $0.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .regular)
        $0.setTitleColor(.white, for: .normal)
        $0.setTitleColor(.white, for: .highlighted)
        $0.setTitleColor(UIColor(white: 0.9, alpha: 10), for: .disabled)
        $0.layer.cornerRadius = 10.5
        $0.layer.masksToBounds = true
        }.onSelected {
            $0.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
        }.onDeselected {
            $0.transform = CGAffineTransform.identity
        }.onTextViewDidChange { (button, textView) in
            button.messageInputBar?.setRightStackViewWidthConstant(to: textView.text.isEmpty ? 0:50, animated: true)
    }
    messageInputBar.setRightStackViewWidthConstant(to: 0, animated: false)

    messagesCollectionView.reloadData()

}

@objc private func cameraButtonPressed() {
    let picker = UIImagePickerController()
    picker.delegate = self

    if UIImagePickerController.isSourceTypeAvailable(.camera) {
        picker.sourceType = .camera } else {
        picker.sourceType = .photoLibrary
    }

    present(picker, animated: true, completion: nil)
}


private func save(_ message: Message) {
    reference?.addDocument(data: message.representation) { error in
        if let e = error {
            print("Error sending message: \(e.localizedDescription)")
            return
        }

        self.partnerReference?.addDocument(data: message.representation) { error in
            if let e = error {
                print("Error sending message: \(e.localizedDescription)")
                return
            }
        }
        self.messagesCollectionView.scrollToBottom()
    }
}


private func insertNewMessage(_ message: Message) {
    guard !messages.contains(message) else { return }

    messages.append(message)
    messages.sort()
    messagesCollectionView.reloadData()

    messagesCollectionView.performBatchUpdates({
        messagesCollectionView.insertSections([messages.count - 1])
        if messages.count >= 2 {
            messagesCollectionView.reloadSections([messages.count - 2])
        }
    }, completion: { [weak self] _ in
        if self?.isLastSectionVisible() == true {
            self?.messagesCollectionView.scrollToBottom(animated: true)
        }
    })
}


    private func handleDocumentChange(_ change: DocumentChange) {
        guard var message = Message(document: change.document) else {
            print("return Message")
            return
        }

        switch change.type {
        case .added:
            print("add Message")
            insertNewMessage(message)
        default:
            break
        }
    }


private func downloadImage(at url: URL, completion: @escaping (UIImage?) -> Void) {
    let ref = Storage.storage().reference(forURL: url.absoluteString)
    let megaByte = Int64(1 * 1024 * 1024)

    ref.getData(maxSize: megaByte) { data, error in
        guard let imageData = data else {
            completion(nil)
            return
        }

        completion(UIImage(data: imageData))
    }
}

func isLastSectionVisible() -> Bool {
    guard !messages.isEmpty else { return false }
    let lastIndexPath = IndexPath(item: 0, section: messages.count - 1)
    return messagesCollectionView.indexPathsForVisibleItems.contains(lastIndexPath)
}

func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) {
    for component in inputBar.inputTextView.components {
        if let str = component as? String {
            let message = Message(user: self.currentUser, content: text)
            save(message)
        } else if let img = component as? UIImage {
            var message = Message(user: self.currentUser, image: img)
            save(message)
        }
    }
    inputBar.inputTextView.text = String()
    messagesCollectionView.scrollToBottom(animated: true)
}

}

扩展MessageKitLogViewController:MessagesDataSource {     func numberOfSections(在messagesCollectionView中:MessagesCollectionView)-> Int {         返回messages.count     }

func currentSender() -> Sender {
    return Sender(id: currentUser.id!, displayName: currentUser.name!)
}

func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int {
    return messages.count
}

func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
    return messages[indexPath.section]
}

func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
    if indexPath.section % 3 == 0 {
        return NSAttributedString(string: MessageKitDateFormatter.shared.string(from: message.sentDate), attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 10), NSAttributedString.Key.foregroundColor: UIColor.darkGray])
    }
    return nil
}

func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
    let name = message.sender.displayName
    return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption1)])
}

func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
    let dateString = formatter.string(from: message.sentDate)
    return NSAttributedString(string: dateString, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption2)])
}

}

扩展MessageKitLogViewController:MessagesLayoutDelegate {

func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
    return .zero
}

func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
    return CGSize(width: 0, height: 8)
}

func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
    return 0
}

}

扩展MessageKitLogViewController:MessagesDisplayDelegate {

func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
    return isFromCurrentSender(message: message) ? Colors.indexedPrimary : .lightGray
}


func shouldDisplayHeader(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Bool {
    return false
}

func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
    let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight : .bottomLeft

    return .bubbleTail(corner, .curved)
}

}

0 个答案:

没有答案