Showing a list of MessageView:
struct ContentView: View {
@ObservedObject var viewModel: ConversationViewModel = ConversationViewModel()
var body: some View {
ForEach(viewModel.messages, id: \.id) { m in
MessageView(message: m)
.id(m.id)
}
}
Provided by the viewModel:
class ConversationViewModel: ObservableObject {
@Published var messages: [Message] = []
}
The Message struct:
struct Message: Identifiable, Equatable {
var id = UUID()
var type: MessageType = .text
var author: MessageAuthor
var body: String = ""
var timestamp: Date = Date()
var failed: Bool = false
var media: URL?
var isLast: Bool = false
static func == (lhs: Message, rhs: Message) -> Bool {
return lhs.id == rhs.id
}
}
And then the MessageView being shown for each message:
struct MessageView: View {
private let message: Message
init(message: Message) {
self.message = message
}
var body: some View {
if message.type == .image {
if (message.media != nil) {
AsyncImage(url: message.media)
} else {
Text("No media.")
}
}
Even once the viewModel makes the message.media take a value instead of being null, the above MessageView always shows "No media.".
The viewModel publishes the messages array, and Message is a struct... I think I'm doing everything right, but I'm obviously missing something here.
Any ideas?
CodePudding user response:
Remove
static func == (lhs: Message, rhs: Message) -> Bool {
return lhs.id == rhs.id
}
SwiftUI will only use the id
to determine if it needs to be redrawn with this implementation.
Just add Hashable
and Equatable
to all the struct
s involved.
Use the default implementation.
CodePudding user response:
try this approach, changing the logic of your MessageView
and
using @StateObject var viewModel = ConversationViewModel()
in ContentView
. And as mentioned, remove static func == ...
.
Works well for me.
struct MessageView: View {
let message: Message // <-- here
var body: some View {
if message.type == .image {
if (message.media != nil) {
AsyncImage(url: message.media)
} else {
Text("No image")
}
} else {
Text("case text presumably") // <-- here
}
}
}
You could also use a switch
instead of if/else
.