【问题标题】:Core Data seems to delete my data right after insertionCore Data 似乎在插入后立即删除了我的数据
【发布时间】:2018-05-23 19:26:15
【问题描述】:

我有很多数据存储在 Core Data 中,没有任何问题。现在我需要添加一些额外的数据。我决定使用要存储的对象(及其所有子对象)实现NSCoding,而不是将对象存储为Transformable(NSObject),而不是为所有这些新数据创建实体。我以前做过这个(在 Obj-c 中),但由于某种原因,这次我不能让它工作。

假设我有一个名为Event:NSObject,NSCoding 的巨大类,其中包含名称、日期和一吨的附加变量。然后想象一下,您希望能够让用户在活动开始前的给定天数收到通知。比如,让用户“观看”事件。我想跟踪正在观看哪些事件,以及我应该在多长时间之前发送通知。有了这个,我可以获得所有“观看”事件的列表,并知道他们想要通知的事件前多少天。这只是真实情况的一个不好的例子,请耐心等待。不要考虑“通知”部分,只是存储数据。

我有我的Event-object,现在我在我的CoreData-database 中创建了一个WatchEvent-entity,它有两个属性:event:Transformabledays:Integer。两者都不是可选的。

我的整个 Event-class 及其所有子类现在都实现了 NSCoding,因此要将其存储在数据库中,我只需将其设置为可转换属性。在这里您可以看到我如何创建WatchEvent-object 并将其放入数据库,以及从数据库中获取所有WatchEvents 的函数,以及打印每个WatchEvent 内容的函数。

func storeWatchEvent(someEvent:Event, numberOfDays:Int){
    let watchEvent = WatchEvent(entity: NSEntityDescription.entity(forEntityName: "WatchEvent", in: managedObjectContext)!, insertInto: managedObjectContext)
    watchEvent.days = numberOfDays //e.g 3
    watchEvent.event = someEvent
    saveContext()
}

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

func getWatchedEvents()->[WatchEvent]?{
    return managedObjectContext.fetch(WatchEvent.fetchRequest())
}

func printOutAllWatchedEvents(){
    if let watchedEvents = getWatchedEvents(){
        watchedEvents.foreach{ (w) in
            print("numberOfDays: ", w.days)
            print("event: ", w.event)
        }
    }
}

func saveButtonClicked(){
    storeWatchEvent(someEvent, numberOfDays:3)

    // For testing, attempt to get all my events immediately, several times
    printOutAllWatchedEvents() //Prints out `numberOfDays: 3` and a valid `event` correctly
    printOutAllWatchedEvents() //Prints out `numberOfDays: 3` and a valid `event` correctly
    printOutAllWatchedEvents() //Prints out `numberOfDays: 3` and a valid `event` correctly
}

func verifyButtonClicked(){
    printOutAllWatchedEvents() //Prints out `numberOfDays: 3` and `nil` for event.
}

假设我有两个按钮。一个“保存”和另一个“验证”。如果单击“保存”,我会保存有效对象,正如您在代码中看到的那样,我会立即在数据库中查询所有存储的 WatchEvent,并将它们打印出来。那时,一切看起来都很好。如果我单击“验证”按钮,它应该打印出相同的内容,但它删除了我的event。它设法保持days-attribute 被存储,但该事件被删除。为什么?:(

等待多长时间单击验证按钮并不重要。如果我几乎同时单击它们,这仍然会发生。

我在 saveButtonClick 中调用了 printOutAllWatchedEvents 三次,由于它每次都设法返回一个有效的事件对象,我假设其中的存储/NSCoding 部分是成功的?

但是,如果我单击验证按钮,我认为这至少会在几个“运行循环”之后发生,可转换的 event-object 已被删除..

我不知道发生了什么。

为什么如果我在插入它们后立即请求它们,它会设法返回我的有效事件,但如果我稍后再请求它们则不会?为什么这只影响transformable 对象?整数days 正确保留给所有WatchEvents。而且由于我已将event 标记为 not 可选,它如何返回 nil 并且从不给我任何错误?我在上下文中调用save 时没有错误,我已经检查过了。

【问题讨论】:

  • 由于您的问题与保存方式有很大关系,因此可以将真实代码替换为do/try managedObjectContext.save() else print out error etc. etc.
  • @AlecO 你是对的。现在添加。而且它永远不会打印出任何保存错误。
  • 首先,检查您的数据库是否存储在存储协调器 (SQL) 文件中的数据现实,这可能是因为您存储和获取的上下文不同?
  • 我不知道我在寻找什么。我已经下载了一个工具来检查实际的 SQLite 文件,并且我看到了我所有的 WatchEvent 对象,并且 event 字段是 empty。我认为这是因为它以某种方式被删除了,因为如果我立即查询它,我确实会在上面的代码中返回它,但也许它根本不会被存储,当我查询它时我收到的是某种缓存? @IraniyaNaynesh 您提供的链接与我的问题完全相反。一开始看不到存储的对象,但后来得到它。我一开始可以看到他们,但以后再也看不到了。会调查。

标签: ios swift core-data


【解决方案1】:

我想通了.. 它与 CoreData 无关,真的。这是NSCoding 的错误实现。我从来没有遇到任何类型的错误,所以很难弄清楚,特别是有这么多变量,但问题本质上是这样的:

class Event:NSObject,NSCoding{

    let hasBeer:Bool

    func encode(with aCoder: NSCoder) {
        aCoder.encode(hasBeer, forKey: "hasBeer")
    }
    required init?(coder aDecoder: NSCoder) {
        //This line:
        self.hasBeer = aDecoder.decodeObject(forKey: "hasBeer") as? Bool ?? false
        //Should be like this:
        self.hasBeer = aDecoder.decodeBool(forKey: "hasBeer")
        //Because it is a primitive type Bool, and not an Object of any kind.
        super.init()
    }
}

我仍然不完全确定为什么我会经历这样的事情..

编码总是成功的,所以事件存储在数据库中(即使在使用Liya检查sqlite文件中的blob字段时它看起来是空的)。它成功编码是因为所有类型(Bool、Int、Double 和 NSObject)的函数名称都相同。他们都使用aCoder.encode(whatever, forKey: "whatever")。但是,在解码它们时,您必须选择正确的解码函数,例如decodeBooldecodeInt32decodeObject 等。

正如我所说的,我过去曾在 Objective-C 中这样做过,我完全没有遇到任何问题,因为编码和解码函数都是根据类型命名的([aDecoder decodeBoolForKey:@"key"];[aCoder encodeBool:hasBeer, forKey:@"hasBeer"];) ,并在使用错误的时候抛出编译时错误。

我想如果我的required init? 中有一些fatalError("something") 而不是在事情没有按计划进行时只使用return nil,我会接受这个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    相关资源
    最近更新 更多