通过Realm集合更改进行更新时,UICollectionView崩溃

时间:2019-06-05 11:12:52

标签: swift uicollectionview crash realm messagekit

我正在使用Realm和MessageKit框架在我的应用程序中实现聊天。 MessageKit在内部使用UICollectionView,每个聊天消息都放置在集合视图的自己部分中。

我的聊天消息模型如下:

class ChatMessage: Object {

    @objc dynamic var id: Int = generateMessageId()
    @objc dynamic var timestamp = Date()
    @objc dynamic var senderId: Int = -1    
    @objc dynamic var text: String = ""

    var recipients = List<Recipient>()

    @objc dynamic var receivedByServer = false
    var readReceipts = List<Recipient>()
}

在我的视图控制器中,我有一系列聊天消息声明如下:

var messages: Results<ChatMessage>!
// and in viewDidLoad()...
messages = conversation.messages.sorted(byKeyPath: "timestamp", ascending: true)

此数组用作UICollectionView基础MessageKit的数据源。我正在观察此数组的更改,当我检测到发生更改时,我将按照以下方式相应地更新UICollectionView的各个部分:

notificationToken = messages.observe { [weak self] (changes: RealmCollectionChange) in
    switch changes {
    case .initial:
        print("Messages collection has been populated...")
    case .update(_, let deletions, let insertions, let modifications):
        print("Messages collection has been updated...")
        self?.messagesCollectionView.performBatchUpdates( {
            if modifications.count > 0 {
                print("modifications count: \(modifications.count)")
                self?.messagesCollectionView.reloadSections(IndexSet(modifications))
            }
            if deletions.count > 0 {
                print("deletions count: \(deletions.count)")
                self?.messagesCollectionView.deleteSections(IndexSet(deletions))
            }
            if insertions.count > 0 {
                print("insertions count: \(insertions.count)")
                self?.messagesCollectionView.insertSections(IndexSet(insertions))
            }
        }, completion: { [ weak self] _ in
            print("Scroll to bottom of UICollectionView...")
            self?.messagesCollectionView.scrollToBottom(animated: true)
        })
    case .error(let error):
        print("Error occurred while observing messages: \(error)")
    }
}

最初,此代码似乎可以正常工作,但是随后我开始看到一个问题,该问题似乎与很快发生的多个更新有关。例如,当我发送聊天消息时,服务器将确认已收到该消息,这将导致修改聊天消息对象。当收件人阅读消息时,这也将导致聊天消息对象被更新。在某些情况下,这两个事件会很快发生,因此我认为调用messagesCollectionView.reloadSections(IndexSet(modifications))的代码将运行两次。似乎第二个呼叫实际上是在第一个呼叫仍在处理中时发生的,这导致崩溃。或者至少我认为这是导致问题的原因。

当崩溃发生时,这就是我从Xcode得到的东西:

[CollectionView] An attempt to prepare a layout while a prepareLayout call was already in progress (i.e. reentrant call) has been ignored. Please file a bug. UICollectionView instance is (<MessageKit.MessagesCollectionView: 0x10c01b400; baseClass = UICollectionView; frame = (0 0; 414 896); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x2830aa670>; layer = <CALayer: 0x283ea44a0>; contentOffset: {0, 137}; contentSize: {414, 604}; adjustedContentInset: {88, 0, 429, 0}> collection view layout: <MessageKit.MessagesCollectionViewFlowLayout: 0x10b7069d0>)
[CollectionView] An attempt to update layout information was detected while already in the process of computing the layout (i.e. reentrant call). This will result in unexpected behaviour or a crash. This may happen if a layout pass is triggered while calling out to a delegate. UICollectionViewFlowLayout instance is (<MessageKit.MessagesCollectionViewFlowLayout: 0x10b7069d0>)
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array'

使用Realm集合作为数据源并观察该集合的更改时,这是更新UICollectionView的正确方法还是我做错了所有这些?顺便说一句,由于MessageKit默认将每个聊天消息放入其自己的部分中,因此我正在更新部分(相对于项目)。

0 个答案:

没有答案