Initialize Core Data Objects SwiftUI

I'm trying to initiate the data so when the user installs the app for the first time it has some data. The init is not working, but why?


For CRUD operations on Core Data I'm using an `xcdatamodeld` file with an entity called `ProgrammingLanguage` that has two string attributes: “name” and “creator”. Here is the code:


struct ContentView: View {

    @Environment(\.managedObjectContext) var managedObjectContext

    @FetchRequest(
        entity: ProgrammingLanguage.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \ProgrammingLanguage.name, ascending: true),
        ]
    ) var languages: FetchedResults
   
    init() {

        let language = ProgrammingLanguage(context: self.managedObjectContext)
        language.name = "SwiftUI"
        language.creator = "Some text"
       
        do {
            try self.managedObjectContext.save()
        } catch {
        }
       
    }
   
    var body: some View {
        NavigationView {
            List {
                ForEach(languages, id: \.self) { language in
                    Button(action: {
                    }) {
                        Text("Creator: \(language.creator ?? "Anonymous")")
                    }
                   
                }
            }
        }
    }
}


It's as if it is not saving it. What's going on here? That init should create the data on the db and I would be able to read it on the view...

Accepted Reply

hi,


not very helpful, indeed! i'm sure i had the same problem when i tried to something with coredata in an init.


my suggestion would be that you remove your init(), take the code you have now, and put it into a function called, say, "loadData." modify the code of loadData to be of the form


func loadData() {
  if languages.count == 0 {
    // run the code you run now to create an initial ProgrammingLanguage entity
  }
}


now attach an .onAppear() modifier to your List, as in


.onAppear(perform: loadData)


that should do it. the view will appear -- it will call loadData, which will add the new entity if there's nothing there yet -- and the FetchRequest will recognize the change, re-computing the body property.


i think that should do it.


hope that helps,

DMG

Replies

hi,


i think the first thing to do is to see if there's an error coming back at line 17, so something like this:


do {
  try self.managedObjectContext.save() 
} catch let error as NSError {
  print("Error saving: \(error.localizedDescription), \(error.userInfo)")
}


i'll go out on a limb on this one: the managedObjectContext may not be set correctly. because you've supplied your own init() method, the normal sequencing of identifying the managedObjectContext from the environment may not have taken place yet.


hope that helps,

DMG

The error says:


Error saving: The operation couldn’t be completed. (Foundation._GenericObjCError error 0.), [:]


Not very helpful :/

hi,


not very helpful, indeed! i'm sure i had the same problem when i tried to something with coredata in an init.


my suggestion would be that you remove your init(), take the code you have now, and put it into a function called, say, "loadData." modify the code of loadData to be of the form


func loadData() {
  if languages.count == 0 {
    // run the code you run now to create an initial ProgrammingLanguage entity
  }
}


now attach an .onAppear() modifier to your List, as in


.onAppear(perform: loadData)


that should do it. the view will appear -- it will call loadData, which will add the new entity if there's nothing there yet -- and the FetchRequest will recognize the change, re-computing the body property.


i think that should do it.


hope that helps,

DMG

The init was a noob way of doing it, an example of what I was trying to do. Your answer above is excactly what I was trying to accomplish but I couldn't since every time I called the funcion in the view it would complain since there cannot be some structs or func in the view by itself.


Many thanks!!