Reputation:
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<ProgrammingLanguage>
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...
Upvotes: 2
Views: 2771
Reputation: 11
I have a similar problem. I tried the .onAppear idea, but that doesn't work for me because in my version of Content View there are statements that require a non-empty core data -- it would need something like the UIKit viewWillAppear so that it would load the data before running any of the ContentView, which .onAppear seems not to do. I did solve the problem in another way by calling another struct that first checks if core data is instantiated, seeds the data if necessary, then calls the intended ContentView, but this seems a runaround when it is really a matter of initialization.
Upvotes: 0
Reputation: 3743
I would recommend doing that with the .onAppear()
modifier. In your code example it would be:
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(
entity: ProgrammingLanguage.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \ProgrammingLanguage.name, ascending: true),
]
) var languages: FetchedResults<ProgrammingLanguage>
var body: some View {
NavigationView {
List {
ForEach(languages, id: \.self) { language in
Button(action: {
}) {
Text("Creator: \(language.creator ?? "Anonymous")")
}
}
}.onAppear() {
let language = ProgrammingLanguage(context: self.managedObjectContext)
language.name = "SwiftUI"
language.creator = "Some text"
do {
try self.managedObjectContext.save()
} catch let error {
print(error)
}
}
}
}
}
Hope that'll help! I found the solution here: Apple Developer Forum
Upvotes: 3
Reputation: 29
love seeing SwiftUI, so it seems you need to add a fetch request, it'll bring you an array of the coreData object you're looking for.
add this property right below your @Environment:
@FetchRequest(entity: ProgrammingLanguage.entity(), sortDescriptors: []) var languages: FetchedResults<ProgrammingLanguage>
then you can present it any way you want
hope it helps, Paul Hudson has a great tutorial on CoreData and SwiftUI if you wanna watch it
https://www.hackingwithswift.com/100/swiftui/57
Upvotes: 2