Do I have to save() my NSManagedObjectContext? - ios

I'm quite new to iOS development and have the following question:
I'm using CoreData and I add a Element like this:
NSEntityDescription.insertNewObjectForEntityForName("Foo", inManagedObjectContext: moc) as! Foo
After restarting my App, it's still there. The question is:
When I should use the NSManagedObjectContext.save() function?

You call save when you want to persist your changes to the disk.
Your method inserts a new object into the managedObjectContext. But the managedObjectContext is really just a temporary place to put things. When you create an object in a context, that doesn't automatically persist those changes to the Persistent Store until you call save on it.

Related

CoreStore create object in context without saving to database

I want to solve next problem:
I would like to work with some NSManagedObject in context and change some properties in runtime, but without telling SQLite about any changes in it.
I just want to save NSManagedObject to database when I hit save button or similar.
As I found out from source code demo we need to use beginUnsafe for this purposes (maybe I am wrong)
func unstoredWorkout() -> WorkoutEntity {
let transaction = CoreStore.beginUnsafe()
let workout = transaction.create(Into<WorkoutEntity>())
return workout
}
let workout = unstoredWorkout()
workout.muscles = []
Now when I try to update workout.muscles = [] app crashes with error:
error: Mutating a managed object 0x600003f68b60 <x-coredata://C00A3E74-AC3F-47FD-B656-CA0ECA02832F/WorkoutEntity/tC3921DAE-BA43-45CB-8271-079CC0E4821D82> (0x600001c2da90) after it has been removed from its context.
My question how we can create object without saving it and how we can save it then when we modify some properties and avoid this crash as well.
The reason for the crash is that your transaction only lives in your unstoredWorkout() method, so it calles deinit, which resets the context (and deletes all unsaved objects).
You have to retain that unsafe transaction somewhere to keep your object alive - such as in the viewcontroller that will eventually save the changes.
But I would rather encourage you to think about that if you really want to do that. You might run into other synchronization issues with various context or other async transactions alive, like when API calls are involved.

CoreData - creating new entity - Why don't you need to save this?

I figured you can create new entities (in swift 3) like this:
let person = Person(context: persistentContainer.viewContext)
person.name = "Some Name"
This seems to be it. It saves the new person permanently (I think so, at least).
Why don't you need to call saveContext()of AppDelegate. swift (or persistentContainer.viewContext.save() which is basically the same, right?)?
Every time you change some entity, you need to save it. Why isn't this the case when creating new entities?
Thanks in Advance !!!
According to your comments on your question, you ARE calling saveContext().
Go into your AppDelegate and check out applicationWillTerminate, saveContext() is called there.
In short, if you want to persist the data then yes, you need to call saveContext()
for your anser you have to understand the Core Data stack
https://developer.apple.com/library/ios/documentation/DataManagement/Devpedia-CoreData/coreDataStack.html#//apple_ref/doc/uid/TP40010398-CH25-SW1
Changes that you make to your managed objects are not committed to the parent store until you save the context.

DATAStack library in existing app with working core-data

I have an application in which I already have working core-data and persistent storage functionality. I'd like use DATAStack in this app, but I can't get it to work.
Without DATAStack I had al these standard core-data lazy vars in my AppDelegate. In my ViewController I retrieved the managedObjectContext like this: let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext. Passed the moc variable to the function that would take care of the storing and called moc.save() somewhere down the line. I know that this works, because I also retrieve and show the stored entries on the screen, which also works after completely closing the app. And I inspect the sqlite database with a sqlite database viewer (SQLPro for SQLite Read-Only).
Now with DATAStack I added a new line in my AppDelegate: lazy var dataStack: DATAStack = DATAStack(modelName: "Database"). The name of my database model is indeed Database.xcdatamodeld so the initialisation should be right. In my ViewController I replaced the var moc = ... described above with let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).dataStack.mainContext. Again this moc variable gets passed around and I call moc.save() somewhere down the line, but now it doesn't store anything.. As I described, the only thing that has changed is where the managed object context comes from.
I must be missing something with this library, but I have no clue what I'm missing.
I've also looked at a Sync example (Sync uses DATAStack), but the dataStack object is retrieved in a whole different way there.
Apparently you shouldn't use the mainContext to save, but always a new background context. So the only way to get the right moc is like this:
dataStack.performInNewBackgroundContext() { moc in
//Do things with moc and call moc.save() somewhere
}

Use NSManagedObject in child NSManagedObjectContext instead of its parent

I have two MOCs: the first is the root context. When I save this context, the changes are saved to the persistent store coordinator. The second MOC has the first MOC as the parent. When I save the second MOC, I also have to save the first MOC in order to save the changes in the second MOC to the persistent store coordinator.
I use the second MOC to let the user edit an object. He can save or cancel the changes. When he saves the changes, all MOCs are saved. When he cancels the changes, I call rollback() of the second MOC.
Unfortunately, the object comes from the first MOC. This means, I execute an NSFetchRequest to fetch the object on the first MOC. Then I create the second MOC in which the user can edit the object. But there is a problem: when the second MOC should change something, for example delete an object that is contained in an array of the original object the user wants to edit, this is not possible, because a MOC can only delete objects that have this MOC as the context. But the object was fetched in the first MOC.
That's why I need to "transfer" somehow the object from the first MOC to the second MOC before the user edits the object. I don't want to fetch the object again with a NSFetchRequest or something, there must be a better way…
Is this possible? Or do you recommend to do this completely different, maybe without parent contexts?
This is where the objectID property of NSManagedObject will come in handy.
Ask the object for its ID
let objectID = myManagedObject.objectID
Ask the child context for a managed object with that ID
do {
let childManagedObject = try childContext.existingObjectWithID(objectID)
print("\(newObject)")
} catch {
}
I think you might be complicating your time with this. Unless it is completely necessary for proposed changes to also be saved there should be no reason to have two contexts for this. There are multiple ways for you to handle a temporary data which you can use to compare your actual record to without having it stored twice.
Why don't you just create a copy of the NSManagedObject and handle the information correction by comparison or simply replacing the original NSManagedObject with the data of the copy and then save it? I personally like this setup a bit more since all I have to do is either compare individual properties when update is desired.
When a full update is required than you can simply work directly on the one NSManagedObject without worrying about copies since you will probably be replacing the entire thing anyway. Like I said, there are other ways to handle, but if it is absolutely necessary for you to have both contexts then looking for a comparison of each property value to the replaced value and then simply save the one in the parent context.

get rid of temporary saved managedObjectContext

how can I manage temporary saved CoreData?
as soon as I do something like this:
var myClass: MyClass = NSEntityDescription.insertNewObjectForEntityForName("MyClass", inManagedObjectContext: (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!) as MyClass
it is part of my managedObjectContext and will be saved when i do a context.save(nil)
Is there any way to get an object of the NSManagedObject Class without messing with my current context.
In other words: I want to have optional objects that just end up unused when I don't save them explicitly and i want to have objects that I really want to save persistently.
This answer is late but hopefully helps someone else out there. Yes there is. You create a child context. Do anything you want there. If
you want to keep your changes, save the child context - which does NOT persist data. It notifies parent context of the changes, the changes are now in your main context. You can then perform save on the main context.
let childContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
childContext.parentContext = mainContext
guard let myClass = NSEntityDescription.insertNewObjectForEntityForName("MyClass", inManagedObjectContext: childContext) as? MyClass else {
// something went wrong, handle it here
return
}
// do your thing here
to let the main context know that you want to keep your changes:
do {
try childContext.save() // does not persist anything, just lets know the parent that we are happy with the changes
} catch {
// handle error
}
when you want to NOT keep your changes you can reset:
childContext.reset()
when you want to persist the changes on the main context you do as always:
do {
try mainContext.save()
} catch {
// handle error
}
There is no direct way u can get rid of updated object what you can do is update it again with real data (which is previous data before updating). whenever you update object of 'NSManagedObject' (core data entity object) 'NSManagedObjectContext' captures all the changes and it saves whenever you do save context.
In this type of use case better to use Sqlite database.
You can delete the objects from the managed context before you call context.save, which prevents them from being committed. Assuming you have an NSManagedObjectContext called context and an instance of MyClass called myClass, then the following will work:
context.deleteObject(myClass)
See:
NSManagedObjectContext.deleteObject
Discussion
... If object has not yet been saved to a persistent store, it is simply removed from the receiver.
Of course the decision about which objects to save and which to discard are up to the logic of your application. So before you call save, you need to check all of the inserted, but not yet, committed instances that are registered with the NSManagedObjectContext you're using. You can keep track of that in your application, or perhaps this will be of use:
NSManagedObjectContext.insertedObjects
The set of objects that have been inserted into the receiver but not yet saved in a persistent store. (read-only)

Resources