ошибка дублирования ключей при использовании scrollview для массива observableobject (swift)

#swift #xcode #swiftui

#swift #xcode #swiftui

Вопрос:

Я использую следующий код для отображения сообщений из базы данных firestore:

 struct ChatView: View {
            
    @ObservedObject var chatModel = ChatsViewModel()
           
    var body: some View {
        VStack {
            ScrollView {
                ScrollViewReader {sp in
                    VStack{
                        ForEach(self.chatModel.messages, id: .self) { message in
                            MessageView(message: message).id(message)
                        }
                    }
                    .onChange(of: chatModel.messages.count) { newValue in
                        guard !chatModel.messages.isEmpty else {return}
                        withAnimation{
                            sp.scrollTo(self.chatModel.messages.last)
                        }
                    }
                }
            }
            TextField("Message", text: $message)
            Button(action: {
                self.chatModel.addMessage(message: Message(userId: user1, text: message, time: self.chatModel.generateCurrentTimeStamp()))
                message = ""
                print("button messageId (messageId)")
            }) {
                Text("Send")
            }
        }
        .onAppear {
            chatModel.getChats(user1: user1, user2: user2)
        }
    }
}
  

Код работает, когда я не использую scrollview. Я могу запустить два симулятора, и они «разговаривают» друг с другом. Однако, когда я включаю код scrollview, я понимаю Thread 1: Fatal error: Duplicate keys of type 'Message' were found in a Dictionary. , почему возникает эта ошибка и что я могу сделать, чтобы ее исправить?

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

 @published var messages = [Message]()

    func getChats(user1: String, user2: String) {
            let group = DispatchGroup()
            
            group.enter()
            self.getDocId(user1: user1, user2: user2, group: group)
                
            group.notify(queue: DispatchQueue.main, execute: {
                self.fetchChats()
            })
        }

    func addMessage(message: Message) {
        do{
            let _ = try db.collection("Chats").document(self.docId).collection("messages").addDocument(from: message)
            print("message sent")
        } catch {
            print(error)
        }
    }
    
    func fetchChats() {
        let ref = db.collection("Chats").document(self.docId)
        ref.collection("messages").order(by: "time").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No documents")
                return
            }
            
            self.messages = documents.compactMap { (queryDocumentSnapshot) -> Message? in
                
                return try? queryDocumentSnapshot.data(as: Message.self)
            }
        }
    }
  

И вот сообщение:

 struct Message: Codable, Identifiable, Hashable {
    var id: String? = UUID().uuidString
    @DocumentID var documentId: String?
    var userId: String
    var text: String
    var time: String
    
    init(documentId: String = "",
         userId: String = "",
         text: String = "",
         time: String = "") {
        self.documentId = documentId
        self.userId = userId
        self.text = text
        self.time = time
    }
        
    enum CodingKeys: String, CodingKey {
        case documentId
        case userId
        case text
        case time
    }
}
  

Комментарии:

1. Не могли бы вы показать свое объявление Message ?

2. Я только что отредактировал сообщение

Ответ №1:

Ваше сообщение идентифицируемо, поэтому попробуйте использовать его id там, где это необходимо, следующим образом

 VStack{
    ForEach(self.chatModel.messages) { message in
        MessageView(message: message).id(message.id)
    }
}