Search code examples
swiftcore-datanspredicateswiftuinsfetchrequest

SwiftUI View and @FetchRequest predicate with variable that can change


I have a view showing messages in a team that are filtered using @Fetchrequest with a fixed predicate 'Developers'.

struct ChatView: View {

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Message.createdAt, ascending: true)],
    predicate: NSPredicate(format: "team.name == %@", "Developers"),
    animation: .default) var messages: FetchedResults<Message>

@Environment(\.managedObjectContext)
var viewContext

var body: some View {
    VStack {
        List {
            ForEach(messages, id: \.self) { message in
                VStack(alignment: .leading, spacing: 0) {
                    Text(message.text ?? "Message text Error")
                    Text("Team \(message.team?.name ?? "Team Name Error")").font(.footnote)
                }
            }...

I want to make this predicate dynamic so that when the user switches team the messages of that team are shown. The code below gives me the following error

Cannot use instance member 'teamName' within property initializer; property initializers run before 'self' is available

struct ChatView: View {

@Binding var teamName: String

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Message.createdAt, ascending: true)],
    predicate: NSPredicate(format: "team.name == %@", teamName),
    animation: .default) var messages: FetchedResults<Message>

@Environment(\.managedObjectContext)
var viewContext

...

I can use some help with this, so far I'm not able to figure this out on my own.


Solution

  • had the same problem, and a comment of Brad Dillon showed the solution:

    var predicate:String
    var wordsRequest : FetchRequest<Word>
    var words : FetchedResults<Word>{wordsRequest.wrappedValue}
    
        init(predicate:String){
            self.predicate = predicate
            self.wordsRequest = FetchRequest(entity: Word.entity(), sortDescriptors: [], predicate:
                NSPredicate(format: "%K == %@", #keyPath(Word.character),predicate))
    
        }
    

    in this example, you can modify the predicate in the initializer.