Reputation: 396
I have been working on a project and have an existing object I am using. I am trying to find a simply way to save, retrieve and delete a list of these objects in Core Data.
Here is my object
import Foundation
class Book : Codable {
var coverIndex:Int?
var authorName:[String]?
var title:String?
var editionCount:Int?
var firstPublishYear:Int?
var key: String?
var publishPlace:[String]?
var publisher:[String]?
public enum BookResponseCodingKeys: String, CodingKey {
case coverIndex = "cover_i"
case authorName = "author_name"
case editionCount = "edition_count"
case firstPublishYear = "first_publish_year"
case key = "key"
case title = "title"
case publishPlace = "publish_place"
case publisher = "publisher"
}
public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: BookResponseCodingKeys.self)
self.coverIndex = try container.decodeIfPresent(Int.self, forKey: .coverIndex)
self.authorName = try container.decodeIfPresent([String].self, forKey: .authorName)
self.editionCount = try container.decodeIfPresent(Int.self, forKey: .editionCount)
self.firstPublishYear = try container.decodeIfPresent(Int.self, forKey: .firstPublishYear)
self.key = try container.decodeIfPresent(String.self, forKey: .key)
self.title = try container.decodeIfPresent(String.self, forKey: .title)
self.publishPlace = try container.decodeIfPresent([String].self, forKey: .publishPlace)
self.publisher = try container.decodeIfPresent([String].self, forKey: .publisher)
}
}
What is the most straightforward to save this in Core Data (or to map it to a Core Data model.)
Upvotes: 5
Views: 12137
Reputation: 1264
In your xcdatamodeld
define an entity, such as User
:
Add an attribute with a Transformable type. Name it 'books'.
Next, set the Transformable attribute's class to an array of Book. In the Custom Class
field below.
Use the following code to get the current array from your current context. These methods should go in some sort of DataManager class (which should be a singleton):
import CoreData
open class DataManager: NSObject {
public static let sharedInstance = DataManager()
private override init() {}
// Helper func for getting the current context.
private func getContext() -> NSManagedObjectContext? {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }
return appDelegate.persistentContainer.viewContext
}
func retrieveUser() -> NSManagedObject? {
guard let managedContext = getContext() else { return nil }
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
do {
let result = try managedContext.fetch(fetchRequest) as! [NSManagedObject]
if result.count > 0 {
// Assuming there will only ever be one User in the app.
return result[0]
} else {
return nil
}
} catch let error as NSError {
print("Retrieving user failed. \(error): \(error.userInfo)")
return nil
}
}
func saveBook(_ book: Book) {
print(NSStringFromClass(type(of: book)))
guard let managedContext = getContext() else { return }
guard let user = retrieveUser() else { return }
var books: [Book] = []
if let pastBooks = user.value(forKey: "books") as? [Book] {
books += pastBooks
}
books.append(book)
user.setValue(books, forKey: "books")
do {
print("Saving session...")
try managedContext.save()
} catch let error as NSError {
print("Failed to save session data! \(error): \(error.userInfo)")
}
}
}
You'll also need a method to create a user (and likely delete, assuming we want to follow CRUD). First, you'll need to grab a reference to the User Entity to create one. This definition should be at the top of your DataManager class.
extension DataManager {
private lazy var userEntity: NSEntityDescription = {
let managedContext = getContext()
return NSEntityDescription.entity(forEntityName: "User", in: managedContext!)!
}()
}
And then implement this function to create one.
extension DataManager {
/// Creates a new user with fresh starting data.
func createUser() {
guard let managedContext = getContext() else { return }
let user = NSManagedObject(entity: userEntity, insertInto: managedContext)
do {
try managedContext.save()
} catch let error as NSError {
print("Failed to save new user! \(error): \(error.userInfo)")
}
}
}
Now just call:
DataManager.sharedInstance.createUser()
to create a new user. Then, to append books to the user's storage:
DataManager.sharedInstance.saveBook(book)
Upvotes: 11
Reputation: 169
It depends on how you want to work with your object. You could inherit your object from NSManagedObject or establish mapping from NSManagedObject consisting your object data to your class.
If you won't inherit your object from NSManagedObject, you could use code like this:
func save(bookObject: Book, in container: NSPersistentContainer) -> NSManagedObject {
container?.performBackgroundTask { context in
do {
// Create NSManagedObject backed object
let bookEntity = BookEntity(context: context)
bookEntity.coverIndex = bookObject.coverIndex
// And all the rest properties
try context.save()
} catch (let error) {
print(error)
return
}
}
}
Upvotes: 0