初始化核心数据托管对象

时间:2017-04-05 23:50:51

标签: swift core-data ios8 ios9

核心数据新手,我有两个问题:正确初始化NSManagedObject并在便捷和指定初始值设定项之间保留其值。

我的AnalyticsEvent NSManagedObject子类中的代码:

@NSManaged public var eventName: String?
@NSManaged public var type: String?
@NSManaged public var reference: String?
@NSManaged public var timestamp: Double

public required init() {

    // Initialize CoreData stack...
    let manager = CoreDataManager(modelName: "Analytics", storeName: "Analytics")

    // I'm not sure what I should be using to instantiate a new entity here...
    // I believe the entity(forEntityName:in:) class method should return an existing value stored in managedObjectContext...
    let event = NSEntityDescription.entity(forEntityName: "Event", in: manager.managedObjectContext!)

    // ... and insertNewObject(forEntityName:into:) to create a placeholder
    // for my new object until I issue saveContext() on managedObjectContext.
    // This isn't working right now, so comment out following line
    //let event = NSEntityDescription.insertNewObject(forEntityName: "Event", into: database.managedObjectContext!) as! AnalyticsEvent
    super.init(entity: event!, insertInto: database.managedObjectContext)

    let customProperties = CustomProperties()
    self.customPropertiesData = NSKeyedArchiver.archivedData(withRootObject: properties) as Data
    self.timestamp = Date().timeIntervalSince1970
}

public convenience init(eventName: String) {
    self.init()

    // At this point the data set in my designated initializer (above),
    // the values have been lost. For example, timestamp == 0
    self.eventName = eventName
    self.type = EventType.discreteEvent
}

谢谢!

修改

进一步调查可能会发现super.init(entity:insertInto:)电话可能会调用我的便利初始化程序,如果是,我不知道它是如何找到便利初始化程序的选择器......但是它可以解释为什么它的值(例如时间戳)没有被保留 - 因为它是对象的新实例?!嗯...

编辑2:

我忘了提到我在执行命中行时遇到此运行时错误:

self.eventName = eventName

CoreData:错误:将托管对象0x7fa2da54da90(0x7fa2da54da40)从其上下文中删除后进行变更。

1 个答案:

答案 0 :(得分:0)

认为这里发生的事情是你需要让init()也成为一个便利初始化程序,并且在该调用中self.init(entity: event!, insertInto: database.managedObjectContext)(而不是super })。

编辑:我今天通过尝试创建一个最小的工作示例,但未能得到错误,再看看这个。

我正在使用一个名为User property的{​​{1}}实体:

import Foundation
import CoreData

@objc(User)
public class User: NSManagedObject {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<User> {
        return NSFetchRequest<User>(entityName: "User")
    }

    @NSManaged public var name: String?

    convenience init() {
        let context = CoreDataManager.shared.persistentContainer.viewContext
        self.init(context: context)
        self.name = "Mathew"
    }

    convenience init(named name: String) {
        self.init()
        self.name = name
    }
}

CoreDataManager只是Xcode的自动生成代码,但移入了它自己的对象:

import Foundation
import CoreData

class CoreDataManager {

    static let shared = CoreDataManager()

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "CoreDataInit")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

当我尝试测试时,我得到了预期的行为:

_ = User()
_ = User(named: "Marge")
_ = User(named: "Homer")

let fetchUsers: NSFetchRequest<User> = User.fetchRequest()

if let results = try? CoreDataManager.shared.persistentContainer.viewContext.fetch(fetchUsers) {
print("there are", results.count, "users")

for user in results {
    print("user is", user.name!)
}

// prints:
// Mathew
// Marge
// Homer

然而,在User课程中,当我离开单身人士到创建CoreDataManager的新实例时,例如

//let context = CoreDataManager.shared.persistentContainer.viewContext
let context = CoreDataManager().persistentContainer.viewContext

此更改触发了'CoreData:错误:在托管对象从其上下文中删除后对托管对象进行了变更。错误。

因此,我对您的错误的第二个诊断是它来自不使用相同的持久性存储协调器(以及不同的上下文)。

如果你的持久存储是可配置的(例如传递模型的名称)很重要,那么我认为最好转换到将上下文传递给NSManagedObject初始化器,这似乎是更像是一个常见的CoreData模式。

一个漫无边际的答案,但希望这次不是红鲱鱼!