Reputation: 343
I´m trying to save an array of structs into coredata. I did a lot of research, but i cannot find the solution. Here´s what i´ve got:
import Cocoa
import CoreData
class ViewController: NSViewController {
struct StudentsStruct {
let firstName: String
let lastName: String
let age: Int
}
let Studentsdata: [StudentsStruct] = [StudentsStruct(firstName: "Albert", lastName: "Miller", age: 24), StudentsStruct(firstName: "Susan", lastName: "Gordon", age: 24), StudentsStruct(firstName: "Henry", lastName: "Colbert", age: 24)]
override func viewDidLoad() {
super.viewDidLoad()
let student: Student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
for items in Studentsdata {
student.firstName = StudentsStruct.firstName
student.lastName = StudentsStruct.lastName
student.age = StudentsStruct.age
}
DatabaseController.saveContext()
let fetchRequest: NSFetchRequest<Student> = Student.fetchRequest()
print (student)
}
}
The DatabaseController is solution i´ve got from this tutorial: https://www.youtube.com/watch?v=da6W7wDh0Dw It´s not so important, it´s just making the "getContext" function. Whats important, in teh commandline "student.firstName = StudentsStruct.firstName" i´m getting the error "instance member "firstName" cannot be used on type ViewController.StudentStruct. After trying and trying, i´m running out of ideas how to get the array of structs into coredata.
This is the DatabaseController file:
import Foundation
import CoreData
class DatabaseController {
private init() {
}
class func getContext() -> NSManagedObjectContext {
return DatabaseController.persistentContainer.viewContext
}
// MARK: - Core Data stack
static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "StudentCoreFile")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error)")
}
})
return container
}()
class func saveContext () {
let context = DatabaseController.persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
for any help thanks in advance!
Ok, you are right, i forgot to execute the fetchrequest. Here´s my current code:
import Cocoa
import CoreData
class ViewController: NSViewController {
struct StudentsStruct {
let firstName: String
let lastName: String
let age: Int
}
let Studentsdata: [StudentsStruct] = [StudentsStruct(firstName: "Albert", lastName: "Miller", age: 24), StudentsStruct(firstName: "Susan", lastName: "Gordon", age: 24), StudentsStruct(firstName: "Henry", lastName: "Colbert", age: 24)]
override func viewDidLoad() {
super.viewDidLoad()
let student: Student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
for item in Studentsdata {
let student: Student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
student.firstName = item.firstName
student.lastName = item.lastName
student.age = Int16(item.age)
}
DatabaseController.saveContext()
let fetchRequest: NSFetchRequest<Student> = Student.fetchRequest()
do {
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
print("number of results: \(searchResults.count)")
for result in searchResults as [Student] {
print(student)
}
} catch {
print ("error")
}
}
}
It´s running without errors. Now i´m getting 32 search results. Every entry is: age = 0; firstName = nil; lastName = nil;
For comparison, this code, without the loop is working:
import Cocoa
import CoreData
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let student: Student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
student.firstName = "henry"
student.lastName = "miller"
student.age = 22
DatabaseController.saveContext()
let fetchRequest: NSFetchRequest<Student> = Student.fetchRequest()
do {
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
print("number of results: \(searchResults.count)")
for result in searchResults as [Student] {
print(student)
}
} catch {
print ("error")
}
}
}
Upvotes: 2
Views: 4204
Reputation: 596
Perhaps this is lazy. You could also just encode your array as a json object and then create a field on your NSManagedObject for it as a transformable. When you want to retrieve you'd just decode and downcast to the proper type. That's what I did in one of my projects; worked fine.
Upvotes: 0
Reputation: 343
In case someone is interested, I found the solution: You first have to set up the struct in the CoredataEntity Class like that:
import Foundation
import CoreData
struct StudentsStruct {
let firstName: String
let lastName: String
let age: Int
}
@objc(Student)
public class Student: NSManagedObject {
@NSManaged public var firstName: String?
@NSManaged public var lastName: String?
@NSManaged public var age: Int16
var allAtributes : StudentsStruct {
get {
return StudentsStruct(firstName: self.firstName!, lastName: self.lastName!, age: Int(self.age))
}
set {
self.firstName = newValue.firstName
self.lastName = newValue.lastName
self.age = Int16(newValue.age)
}
}
}
Then use the same struct to paste the data:
import Cocoa
import CoreData
class ViewController: NSViewController {
let studentsdata: [StudentsStruct] = [StudentsStruct(firstName: "Albert", lastName: "Miller", age: 24), StudentsStruct(firstName: "Susan", lastName: "Gordon", age: 24), StudentsStruct(firstName: "Henry", lastName: "Colbert", age: 24)]
override func viewDidLoad() {
super.viewDidLoad()
for items in studentsdata {
let student: Student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
student.allAtributes = items
}
DatabaseController.saveContext()
let fetchRequest: NSFetchRequest<Student> = Student.fetchRequest()
do {
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
print("number of results: \(searchResults.count)")
for result in searchResults as [Student] {
print("student: \(firstName), \(lastName), \(age)" )
}
} catch {
print ("error: \(error)")
}
}
}
Thats it.
Upvotes: 3
Reputation: 72460
You need to access the item
in your for loop also you are currently accessing the same object Student
object in for loop instead of that you need to create a new Student
in every iteration of for loop.
for item in Studentsdata {
//Create new student in for loop
let student = NSEntityDescription.insertNewObject(forEntityName: "Student", into: DatabaseController.getContext()) as! Student
//To get firstName, lastName and age access the item
student.firstName = item.firstName
student.lastName = item.lastName
student.age = item.age
}
//Save context now
DatabaseController.saveContext()
Upvotes: 3