Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I transform SwiftUI fetch request results based on related objects?

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?

like image 572
Jaanus Avatar asked Jan 27 '26 19:01

Jaanus


1 Answers

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
}
like image 196
Asperi Avatar answered Jan 29 '26 12:01

Asperi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!