3 Replies
      Latest reply on May 13, 2020 5:25 PM by DelawareMathGuy
      afern247 Level 1 Level 1 (0 points)

        How can I get the fetch request from a different class so I can re-use it on different views and functions on other files? If you see on the code below, I have to call the fetch request twice in different classes, I want to create a class with a function called: readData so when I call it: readData() it will return the @FetchRequest . I'm using SwiftUI. This is the code I was mentioning:

         

        import SwiftUI
        
        struct ContentView: View {
        
        @ObservedObject var myClass = MyClass()
        
        @FetchRequest(
          entity: ProgrammingLanguage.entity(),
          sortDescriptors: [
          NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
          ]
        ) var languages: FetchedResults
        
        @Environment(\.managedObjectContext) var managedObjectContext
        
        var body: some View {
        
          NavigationView {
          VStack {
          List(languages, id: \.self) { language in
          Text(self.language.name ?? "")
          }
          }
          }
          .onAppear{
          // Data not refreshed
          self.myClass.createData()
          }
        }
        }
        
        class MyClass: ObservableObject {
        
        @FetchRequest(
          entity: ProgrammingLanguage.entity(),
          sortDescriptors: [
          NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
          ]
        ) var languages: FetchedResults
        
        @Environment(\.managedObjectContext) var managedObjectContext
        
        func createData() {
          for i in 1...5 {
          let language = ProgrammingLanguage(context: self.managedObjectContext)
          language.id = Int32(i) // << here !!
          language.name = "\(i) SwiftUI"
          do {
          try self.managedObjectContext.save()
          } catch {
          }
          }
        }
        
        func readData() {
          // How can I return the objects here? Not in a loop, but as a fetch request so I can use that fetch request on other views
        }
        }
        • Re: Get fetch request from a different class/function
          DelawareMathGuy Level 3 Level 3 (210 points)

          hi,

           

          there's a lot going on with your code and with your question, so here are a few comments.

           

          (1)  your ContentView (lines 3 - 30) has a @FetchRequest and an @Environment variable that is passed along to you by the SceneDelegate.  in order to display, it uses the @FetchRequest (and its assumed managedObjectContext) to provide a list of ProgrammingLanguage objects (i.e., entities on the CoreData side).  the problem, of course, is that you probably have no CoreData entities, so you rely on using the .onAppear() modifier to go out and add a few ProgrammingLanguages to work with.

           

          you might see this recent thread

           

          (2)  rather than just write a simple function inside ContentView that creates some data, you seem to want to invent a MyClass object that will do it for you.

           

          OK, that design could work -- but your definition of MyClass has a serious problem: even though it has made its own @FetchRequest and @Environment declaration, these are not useful.  these property wrappers make sense for Views and their child views, but they don't mean much to objects defined inside the ContentView.

           

          so the real problem of creating objects in your MyClass.createData function is that there is no managedObjectContext available to it.  we don't know where the ProgrammingLanguage objects are being created, and chances are the try self.managedObjectContext.save()   statement on line 49 simply fails.

           

          (3)  if you do want MyClass to work, kill lines 34 through 41, then ask the createData() function to go find the viewContext of the persistentContainer of the AppDelegate to use, in which to create the objects and save them.  the code would look like this:  (you'll need to import UIKit and CoreData to make this work).

           

          let appDelegate = UIApplication.shared.delegate as! AppDelegate
          let managedObjectContext = appDelegate.persistentContainer.viewContext
          for i in 1...5 {
            let language = ProgrammingLanguage(context: managedObjectContext)
            language.id = Int32(i) // << here !!
            language.name = "\(i) SwiftUI"
            do {
              try managedObjectContext.save()
            } catch let error as NSError {
              print("Error saving ProgrammingLanguages: \(error.localizedDescription), \(error.userInfo)")
            }
          }
          

           

          (4)  if you want MyClass to do its own fetching of ProgrammingLanguage objects (the ContentView does this for you already with its @FetchRequest, so be careful in how you might use it), then you'd need to define it this way:

           

          func readData() -> [ProgrammingLanguage] {
            let fetchRequest: NSFetchRequest<ProgrammingLanguage> = ProgrammingLanguage.fetchRequest()
            fetchRequest.sortDescriptor = NSSortDescriptor(keyPath: \ProgrammingLanguage.id, ascending: true)
            do {
              let appDelegate = UIApplication.shared.delegate as! AppDelegate
              let managedObjectContext = appDelegate.persistentContainer.viewContext
              let languages = try managedObjectContext.fetch(fetchRequest)
              return languages
            } catch let error as NSError {
              print("Error fetching ProgrammingLanguages: \(error.localizedDescription), \(error.userInfo)")
            }
            return [ProgrammingLanguage]()
          }
          

           

          i think this all makes sense ...

           

          hope that helps,

          DMG