如何将现有对象保存到Core Data中?

5

我一直在开展一个项目,使用着一个现有的对象。我正在尝试找到一种简单的方法,在Core Data中保存、检索和删除这些对象的列表。

这是我的对象:

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)
    }
}

什么是将这个内容保存在Core Data中最直接的方法(或将其映射到Core Data模型)?
2个回答

11
在你的xcdatamodeld中定义一个实体,比如Userenter image description here 添加一个转换类型为Transformable的属性。将其命名为'books'。 enter image description here 接下来,在下面的Custom Class字段中将Transformable属性的类设置为一个Book数组。 enter image description here 使用以下代码从当前上下文获取当前数组。这些方法应该放在某种DataManager类中(它应该是一个单例):
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)")
        }
    }

}

您还需要一个创建用户的方法(如果我们想要遵循CRUD,则可能需要删除用户)。首先,您需要获取对用户实体的引用以创建一个。这个定义应该在您的DataManager类的顶部。

extension DataManager {
    private lazy var userEntity: NSEntityDescription = {
        let managedContext = getContext()
        return NSEntityDescription.entity(forEntityName: "User", in: managedContext!)!
    }()
}

然后实现这个函数来创建一个。
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)")
        }
    }
}

现在只需调用以下方法:
DataManager.sharedInstance.createUser()
即可创建一个新用户。 然后,将书籍添加到用户的存储中,可以使用以下方法:
DataManager.sharedInstance.saveBook(book)

非常感谢您的快速回复。我得到了我担心的错误:在User+CoreDataProperties.swift类中,属性不能被标记为@NSManaged,因为它的类型无法在Objective-C中表示。 - AlexK
刚刚注意到这一点。不要子类化 Codable,而是尝试子类化 NSObjectNSCoding。确保实现 encode(with aCoder: NSCoder)init?(coder aDecoder: NSCoder) 方法。 - jake
NSObject和Codable似乎可以工作。让我尝试其余部分。 - AlexK
哎呀,是的,我做了。首先,只需调用createUser()。这只需要运行一次 - 实际上,您可以通过检查retrieveUser()是否返回nil来确保尚未创建用户。然后使用saveBook(book)方法保存您的书籍。使用当前函数,您必须逐个执行此操作,但制作一个用于追加批处理的函数应该非常简单。 - jake
很高兴能够帮助! - jake
显示剩余6条评论

0

这取决于您想如何处理您的对象。您可以从NSManagedObject继承您的对象,或者建立从包含您的对象数据的NSManagedObject到您的类的映射。

如果您不想从NSManagedObject继承您的对象,您可以使用以下代码:

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
            }

        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接