Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI & Core Data - How do I use a parent record in a predicate?

Is it possible to use a core data record in a predicate inside the @FetchRequest property wrapper in SwiftUI?

I have a list of Project and a list of Tasks. I want to tap on a project and navigate to a list of related tasks for that project. I can't seem to find a way to pass in the parent project in a way that SwiftUI can see before the @FetcheRequest is initialized.

I tried placing the parent project in an EnvironmentObject. This is called when I navigate from the ProjectListView to the TaskListView.

TaskListView()
   .environment(\.managedObjectContext, self.managedObjectContext)
   .environmentObject(self.projectToEdit)

Then in the TaskListView I added tried this:

    @Environment(\.managedObjectContext) var managedObjectContext

    @EnvironmentObject var parentProject: Project

    @FetchRequest(
        entity: Task.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Task.name, ascending: true)
        ],
        predicate: NSPredicate(format: String(format: "%@%@", "taskProject", " == %@"), parentProject)
    ) var tasks: FetchedResults<Task>

I get the following error on the line with the predicate.

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

So is there a way to write a predicate in some way that can use the parent project? Passing the project to the task view does not seem like it's going to work. How else would I go about using a record in a predicate like this?

like image 398
radicalappdev Avatar asked Oct 31 '19 12:10

radicalappdev


People also ask

Is SwiftUI same as Xcode?

Xcode and Swift are both software development products developed by Apple. Swift is a programming language used to create apps for iOS, macOS, tvOS, and watchOS. Xcode is an Integrated Development Environment (IDE) that comes with a set of tools that helps you build Apple-related apps.

What is SwiftUI used for?

SwiftUI helps you build great-looking apps across all Apple platforms with the power of Swift — and surprisingly little code. You can bring even better experiences to everyone, on any Apple device, using just one set of tools and APIs.

Is SwiftUI any good?

SwiftUI has proven itself to be an absolute game changer in the world of iOS development due to the fact that SwiftUI offers syntax that is easy to understand and is structured in a way that makes sense. Not only this, but SwiftUI is a much more powerful library.

What is difference between Swift and SwiftUI?

So “SwiftUI” is the thing that draws buttons and stuff, Swift is the language it is written in, and probably the language that a programmer doing a “let's show a list of flowers, let people tap on them, and see details about them” app uses.


1 Answers

The FetchRequest can be dynamically created in the init method. That way you can vary predicate and sort conditions. Here is some sample code to achieve that.

// sample Project class
class Project:NSManagedObject {
    var id : String
    var name : String
}

// sample Task class
class Task:NSManagedObject {
    var id : String
    var prjId : String
    var name : String
}

// Task List View
struct TaskListView: View {
    @Environment(\.managedObjectContext) var managedObjectContext

    private var tasksRequest: FetchRequest<Task>
    private var tasks: FetchedResults<Task> { tasksRequest.wrappedValue }

    private var project:Project

    // init Task with Project
    init(_ project:Project) {
        self.project = project

        // create FetchRequest
        self.tasksRequest = FetchRequest(
            entity: Task.entity(),
            sortDescriptors: [NSSortDescriptor(key: "name", ascending:true)],
            predicate: NSPredicate(format: "prjId == %@", project.id))
    }

    var body: some View {
        VStack {
            Section(header: Text("Tasks under \(project.name):")) {
                // access the fetched objects
                ForEach(tasks, id:\.id) { task in
                    Text("\(task.name)")
                }
            }
        }
    }
}

Then the call to TaskListView() would look like:

// call to TaskListView
TaskListView(self.projectToEdit)
    .environment(\.managedObjectContext, self.managedObjectContext)
like image 166
ddelver Avatar answered Oct 03 '22 01:10

ddelver