0

I am trying to select database items with a predicate before displaying a view and need to pass a property, but I'm in a catch-22 situation since the property may not be initialized, yielding the message: Cannot use instance member 'subject' within property initializer; property initializers run before 'self' is available

struct ShowInfo: View
{
    @State var subject: Subject
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Info.entity(), sortDescriptors: [NSSortDescriptor(key: "title", ascending: true)],
                  predicate: NSPredicate(format: "subject.title == %@", $subject.title)
    ) var infos: FetchedResults<Info>
    @State var size = UIScreen.main.bounds.width / 3
    var body: some View
    {
        List
            {
                Text("Info").font(.system(size: 24)).foregroundColor(Color.green)
                ForEach(infos, id: \.infoid)
                { info in
                    ZStack
                    {
                        if info.subject == self.subject.title
                        {
                            NavigationLink(destination: EditInfoView(info: info))
                            {
                                HStack
                                {
                                    Text(info.title!).frame(width: 150, height: 40).background(Color.blue).foregroundColor(Color.white).cornerRadius(10)
                                    Text(info.value!)
                                }
                            }
                        }
                    }
                }.onDelete(perform: deleteInfo)
        }
    }
}
Russ
  • 467
  • 3
  • 10
  • Does this answer your question? https://stackoverflow.com/questions/57871088/swiftui-view-and-fetchrequest-predicate-with-variable-that-can-change –  Jun 08 '20 at 19:48
  • I now get different errors in the initializer. In the example shown, the words variable is trying to be initialized using data fetched within the initializer, but the initializer complains that not all the properties have been set before leaving the initializer, which is true. Not sure if I should post my continuing question here or in the other response. – Russ Jun 09 '20 at 21:59

2 Answers2

0

The answer found at SwiftUI View and @FetchRequest predicate with variable that can change is essentially correct, but I discovered that the order in which things appear inside the struct matters to avoid a slew of errors.

I modified my code as follows...

struct ShowInfo: View
{
    init (subject: Subject)
    {
        self.subject = subject
        self.infoRequest = FetchRequest<Info>(entity: Info.entity(), sortDescriptors: [NSSortDescriptor(key: "title", ascending: true)],predicate: NSPredicate(format: "subject.title == %@", subject.title!))
    }

    @Environment(\.managedObjectContext) var moc
    var subject: Subject
    var infoRequest: FetchRequest<Info>

    var infos: FetchedResults<Info>{infoRequest.wrappedValue}

This cleared up all the errors and allowed the app to work correctly. When the init() was after the variable declarations, I got the same error as before as well as other errors. The compiler seemed to be getting confused about what had already been initialized and what had not. I'm not sure why the example shown for question 57871088 worked for others and mine required rearranging the declarations.

Russ
  • 467
  • 3
  • 10
0

I thought the above answer solved my problem, and it did in that case, but in another view the same methodology yielded errors claiming that I hadn't initialized all the properties within the init. After much experimenting, I discovered all those errors went away if I commented out the @Environment statement. Of course that generated errors for the undefined variable moc, so I commented that code out to see what happened, then the original errors reappeared. It seems clear that the compiler is getting confused. Does anyone know a way around that issue?

Here's the code I'm working with now:

struct EditSubjectView: View
{
    init(subject: Subject)
    {
        self.subject = subject
        self.formRequest = FetchRequest(entity: Field.entity(), sortDescriptors: [NSSortDescriptor(key: "sequence", ascending: true)], predicate: NSPredicate(format: "subjectid == %@", subject.subjectid!.description))
    }

    @Binding var subject: Subject
    var formRequest: FetchRequest<Field>
    var fields : FetchedResults<Field>{formRequest.wrappedValue}

    @Environment(\.managedObjectContext) var moc

    var body: some View
    {
        return VStack
            {
                    HStack
                    {
                            Text("Subject Title").padding(.leading)
                            //Spacer()
                    }
                    TextField(subject.title!, text: Binding($subject.title)!)
                        .padding(.all)
                        .background(Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0, opacity: 1.0))
                        .cornerRadius(15)
                    Spacer()
                    Button("Save")
                    {

                        do
                        {
                            try self.moc.save()
                        }
                        catch
                        {
                            print(error.localizedDescription)
                        }

                    }.frame(width: 150, height: 30).background(Color.red).foregroundColor(Color.white).cornerRadius(15.0)
            }.padding()
    }
}
Russ
  • 467
  • 3
  • 10