I am building a SwiftUI list where I need a dynamic predicate. The approach is discussed here: https://www.hackingwithswift.com/books/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui
Here is my code so far:
struct SomeView: View {
var collection: Collection
var messages: FetchRequest<Message>
init(collection: Collection) {
let predicate : NSPredicate = NSPredicate(format: "collection = %@", collection)
self.collection = collection
self.messages = FetchRequest<Message>(entity: Message.entity(), sortDescriptors: [NSSortDescriptor(key: "date", ascending: true)], predicate: predicate)
}
var body: some View {
List(messages.wrappedValue, id: \.uniqueIdentifier) { message in
// construct the UI
}
}
}
So far so good.
What I can’t figure out how to do: I need to transform the messages
elements based on some other messages in the results (let’s say based on previous message for simplicity). messages[0] should look a particular way. messages[1] look depends on messages[0]. messages[2] depends on messages[1] and so on. I cannot precompute this, since it may vary across time. It should be computed in the context of this specific fetch request/result.
I could express this as some transient computed property on the Message object, which the view code could then use to branch out. I could have a function where I give a particular message and the array of messages, the function looks up the message and other messages and sets the state of a given message based on that. However, SwiftUI limits what I can do in View code, I can’t execute functions this way.
I can run map or flatmap where I access the wrappedValue, but those don’t let me access other elements of the collection to make decisions (I think?).
How would I run this kind of transformation in this context?
If I correctly understood your description (and taking into account that FetchedResults
is a RandomAccessCollection
) I would go with the following approach
var body: some View {
List(messages.wrappedValue, id: \.uniqueIdentifier) { message in
rowView(for: message, from: messages.wrappedValue)
}
}
func rowView(for message: Message, from result: FetchedResults<Message>) -> some View {
// having .starIndex, .endIndex, .position, etc. do any dependent calculations here
// and return corresponding View
}