1

I use a CoreData Model where a Group Object has GroupMembers(firstName: String) connected with the entity members. GroupMembers have a corresponding property group that connects back to the Group Object. In my Detailview I transfer an group Object. In a FetchRequest I want to filter all GroupMembers that have the same Group as my transfered group.

I use the following code:

struct GroupDetailView: View {
    @ObservedObject var group: Group
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \GroupMember.firstName_, ascending: true)],
        predicate: NSPredicate(format: "group == %@", group),
        animation: .default)
    private var members: FetchedResults<GroupMember>
    
    var body: some View {

    }
}

But I get the following error:

Cannot use instance member 'group' within property initializer; property initializers run before 'self' is available
hfs23
  • 125
  • 1
  • 1
  • 9
  • it happens because you're using `group` before initializing it, so you're using an empty `Group` object in your `FetchRequest` – grandsirr Oct 26 '22 at 15:43
  • Do you have any idea how I can fix this? – hfs23 Oct 26 '22 at 16:03
  • 1
    Does this answer your question? [Is there a way to modify fetched results with a predicate after they are initialized?](https://stackoverflow.com/questions/59344515/is-there-a-way-to-modify-fetched-results-with-a-predicate-after-they-are-initial) – grandsirr Oct 26 '22 at 16:13
  • 1
    Do you really need Group as an ObservedObject in that view? Maybe this can be solved by a simple re-design like writing a custom init that takes a Group as an argument and uses that group to create the predicate and assign it to the fetch request – Joakim Danielson Oct 27 '22 at 12:19
  • Or the other way around, do you need the fetch request at all? Can’t you get all GroupMember objects using the relationship attribute for Group -> GroupMember? – Joakim Danielson Oct 27 '22 at 12:22
  • I see this question now has an accepted answer but I am now convinced the right solution is what I mentioned in my previous comment, skip the fetch request all together and get the objects from the Group object instead. – Joakim Danielson Oct 27 '22 at 19:38

1 Answers1

2

Here is one way:

struct GroupDetailView: View {

    private var fetchRequest: FetchRequest<GroupMember>
    private var members: FetchedResults<GroupMember> {
        fetchRequest.wrappedValue
    }
    
    init(group: Group) {
        fetchRequest = FetchRequest(sortDescriptors: [SortDescriptor(\.firstName)], predicate: group.membersPredicate)
    }

    var body: some View {

    }
}

You might not have seen the request and results broken up like this, the source of that idea is a comment in the header file for @SectionedFetchRequest.

You also need to add the lazy var to your Group class extension to hang on to the NSPredicate object so it can be reused if this View is init again. In the Model editor, for Group choose generate class extension only. Then in Editor menu, choose create NSManagedObject subclass, pick the folder where the swift files are and select the app's target. It makes both files so delete the class extension and keep the class. You might need to clean build a few times for it to stop using its auto-generated class file. Then edit it to this:

import Foundation
import CoreData

@objc(Group)
public class Group: NSManagedObject {

    lazy var membersPredicate = {
        NSPredicate(format: "group = %@", self)
    }()
}
malhal
  • 26,330
  • 7
  • 115
  • 133