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 structs 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.
