I have a lot of data stored in Core Data without any trouble. Now I need to add some additional data. Instead of creating an entity for all this new data, I have decided to use the fact that the object to be stored(and all its children) implement NSCoding
, and rather store the object as a Transformable
(NSObject). I have done this before (in Obj-c), but for some reason I can't get it to work this time.
Let's say I have a huge class named Event:NSObject,NSCoding
which contains name, date, and a metric ton of additional variables. Then imagine you'd want the ability to let the user receive a notification a given number of days before the event starts. Like, let the user "watch" the event. I want to keep track of which events are being watched, and how long before I should send the notification. With this, I can get a list of all the "watched" events, and know how many days before the event they want a notification. This is just a poor example of the real situation, just bear with me. Don't think about the "notification" part, just storing the data.
I have my Event
-object, now I have created a WatchEvent
-entity in my CoreData
-database which has two attributes: event:Transformable
and days:Integer
. Neither are optional.
My entire Event-class and all its children now implement NSCoding, so to store this in the database, I simply set it to the transformable attribute. Here you can see how I create the WatchEvent
-object and put it in the database, and a function to get all WatchEvents
from the DB, and a function to print out the contents of each 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.
}
Let's say I have two buttons. One "Save" and another "Verify". If I click "Save", I save the valid objects, and as you can see in the code, I immediately query the database for all stored WatchEvents, and print them out. At that time, everything looks good. If I click the "verify"-button, it should've printed out the same thing, but it has deleted my event
. It manages to keep the days
-attribute stored, but the event is deleted. Why?:(
It doesn't matter how long I wait to click the verify-button. If I click them nearly at the same time, this still happens.
I call printOutAllWatchedEvents
in saveButtonClick, three times, and since it manages to return a valid event-object every time, I assume that the storing/NSCoding-part of this was successful?
But if I click the verify-button, which I assume will happen at least a few "run loops" later, the transformable event
-object has been deleted..
I have no idea what's happening.
Why does it manage to return my valid events if I request them immediately after inserting them, but not if I request them later? Why does this only affect the transformable
object? The integer days
is correctly retained for all WatchEvent
s. And since I have marked event
as not optional, how can it return nil and never give me any errors? There are no errors when I call save
on the context, I have checked.