Best way to 'dump' a Core Data stack? - ios

My app needs to be able to disconnect from a server and connect to another one at whim, which necessitates dumping whatever persistent store we have. Issue here is that releasing the 'main' managed object context means whatever objects in it that I have laying around fault, which causes all sorts of unexpected little issues and crashes.
Is there a better way to 'reset' my stack/managed objects littered around the program than just calling release on everything in my Core Data stack?

You need to close down you Core Data stack from the top down.
Make sure that no managed objects are retained by any object other than the managed object context e.g. make sure the objects aren't held in an array owned by a UI controller.
Save the managed object context to clean up any loose ends.
Fully release the context and nil it. The context should never be retained by more than one object e.g the app delegate, anyway.
Send removePersistentStore:error: to the persistent store coordinator.
Use standard file operations to delete the actual store file.
Changing Core Data like this on the fly is difficult because Core Data isn't just a little database hung off the side of the app. It is intended to serve as the apps entire model layer. Since Apple is really into Model-View-Controller design, then the model is the actual core of the program (hence Core Data's name.) As such, you can't really turn it on and off the way you would a mere SQL database.
You might actually want to rethink your design so that you can change servers without having to shut down your entire data model. E.g. simply delete all managed objects associated with an unused server.

If you mean you want to fault all objects so they will be fetched again from your persistent store,
[managedObjectContext reset];

Related

CoreData - Making Objects That May Or May Not Be Stored

I have an existing iOS project which I'm trying to change to use CoreData instead of Keyed Archiving. In my existing project, I often create objects when the user closes a modal view. Then I do some validation on that object, and if all is well I go ahead and store it. But if the object is determined to be invalid, I simply throw it away and throw up a validation message to the user.
I got nervous about this pattern when I started using Core Data. I didn't want to keep creating "temporary" objects in my database only to turn around and delete them. So instead I create the objects without assigning them to a NSManagedObjectContext. Then later when I determine things are valid, only then do I assign it to a context.
At last here's the question: Is this a valid approach? Are things commonly done this way? I'm worried as my use of managed objects gets more complicated, with more relationships between entities, that I may regret this choice. Am I unnecessarily making things harder for myself?
A common way to do this is to create a child conteit of the main context. You can create your objects in that context, and if you want to save the changes to the main context and then save the main context. If you don’t want to keep the changes just throw away the child context.

CoreData in-memory setup with MagicalRecord 3

Hello I'm using CoreData + MagicalRecord 3 to manage the data in my app. Until then everything was working fine, but then I realize in production than my app is freezing like hell !
So I started to investigate knowing about the fact that to not stuck the UI, it's better to have a main context and a background context and save stuff in background etc...
Nevertheless I have to question due to my setup. I use CoreData in-memory store system (for the best performance) and I don't care about storing the data on disk of my app, I'm fine with a volatile model that will be destroyed when the app is killed or in background for too long. I just want to be able to find my data from any view controller and without coupling.
So I have few questions :
1) If I would use 1 unique context, what would happen if I NEVER save it to the memory store ? For instance if I MR_createEntity then I retrieve this entity from the context and update it, is it updated everywhere or do I have to save it so it can be updated ? In other term was is the interest of saving for in-memory where you don't want to persist the data forever ?
2) If I use 1 unique context that I declare being background, if I display my screen before my data is finished to saved, the screen won't be able to find and display my data right ? Unless I use NSFetchResultController right ?
1) you want to save your data even with an in memory store for a couple of reasons. First, so that you can use core data properly in the case where you might change your mind and persist your data. Second, you'll likely want to access and process some data on different threads/queues. In that case, you'll have to use Core Data's data safety mechanisms for threads/queues. The store is the lowest level at which Core Data will sync data across threads (the old way). This may be less important if you use nested contexts to sync your data (the new way). But even with nested contexts, you'll need call save in order for your changes to merge across contexts. Core Data doesn't really like it when you save to a nil store.
2) You can make and use your own context for displaying data. NSFetchedResultsController does a lot of the leg work in listening for the correct notifications and making sure you're getting very specific updates for the data you asked for in the first place. NSFRC is not always necessary, but will certainly be the easiest way to start.

Frequently Accessed Objects/Classes

Within my Swift application, there are two classes that I interact with in almost 75% of the app. One is a set of settings called UserSettings, and the other is called Job. These both are stored in sqllite.
Most of the time it's just reading values already set, and on one areas it also writes. It seems strange to have to keep reinstantiating my settings and job services to communicate with my database to get back to me the same object i'm accessing across the board.
In a case like this, the options to me see to be either
constantly reading/writing to the database, or
do some sort of singleton accessed throughout the entire app.
I'm not sure how much Swift changes anything in terms of arriving at an answer to this question, but I wanted to seek the help of Stack Overflow. How do I set an object that I can access throughout the entire app? Or is it not ideal and instead I need to get it from my db every time?
Thanks so much.
I recommend you to read how core data works, I know you are managing your own store, but the architecture works fine. As a summary you can create a "context object"(this could be your singleton) who interacts with your store (sqlite) creating managed objects, you will work with this objects who are associated with the "context object", and when ever you need to save the changes, you ask the "context object" to write all the managed objects in the store.
Your managed objects need to be only a copy of the "context object" objects, so when you ask to "save" data to the "context object" you only copy back this managed objects. This will help with save multithread coding. (Your context object should work on a serialized queue).
Again this is just a summary, you should read how core data works to get a better picture.
Edit:
Read this blog: http://www.objc.io/issue-4/core-data-overview.html
The difference is that you only need one store and one context object.

Can you edit the same NSManagedObject in 2 different ManagedObjectContexts and merge their changes?

I'm syncing with a MySQL database.
Initially, I was going to loop through all my new/modified objects and set all the foreign keys for that object and then do the next object, and so on... But that's a lot of fetch requests.
So instead I wanted to loop through all my new/modified objects and set the foreign keys one at a time. So the first pass over my objects sets fk1, my next sets fk2, so on...
Cool, fetch requests drastically reduced. Now I'm curious if I could thread these fk setters. They aren't dependent on each other, but they are modifying the same object, even though they're only setting one relationship, and it's a different relationship. Speaking in git terms, these changes could be 'merged' together without any conflict, but is it possible to push changes in one child managedObjectContext(childContext:save) up to the parentManagedObjectContext(parent:performBlock^{parent:save}) and pull it down in another, different child managedObjectContext(???)? Or will the merge policy only take one childContext's version of the object and leave the other fks effectively unchanged.
I know this exists: NSManagedObjectContext/refreshObject:mergeChanges:
But that's on an object by object level. Will that cause a bunch of fetches? Or will that update my whole context at once/in batches?
Following Apple's suggestion from here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html
I've created/updated my values before I start setting any relationships, so all entities already exist before I try to point any relationships at them.
Aside: We have a couple apps that could benefit from the concurrency, because they throw a considerable amount of data around, and with the quad core iPad apps, this would really help out with the time the initial sync takes.
I'n not sure what you are trying to do and why (you could write less lines in your question and be more clear), but here are some guidelines for working with Core Data:
-- NSManagedObjectContext is not thread safe. Therefore, you need to limit your access to this managed object context to happen inside 1 thread. Otherwise, you may end up having many errors you can't understand.
-- NSManagedObjectContexts apart from doing other things, serve like "snapshots" of your persistent store. That means that when you change an object, you save it to the persistent store, you post a NSManagedObjectContextDidSaveNotification and then call mergeChangesFromContextDidSaveNotification: in another place inside your program in order to load the latest data from the persistent store. Be careful of thread safety.
NSManagedObjectContext/refreshObject:mergeChanges: according to apple is not about just refreshing a managed object. If you pass YES as the second argument, it will write any pending changes from this managed object context to the persistent store, and will load any other changes to other properties of this object from the persistent store, thus "synchronizing" your object with the persistent store. If you pass NO as the second argument, the object loses any pending changes, and it is being turned to a fault. That means that when you attempt to access it, the Managed Object Context will reload the object as it was last saved to the database. It will NOT reload the entire managed object context. It will only operate on the object.
Aside: I have written a blog post that scratches the surface of asynchronous loading from a core data database. In my case, since I'm doing heavy lifting with the database, I ended up using an NSOperation that operates with its own NSManagedObjectContext, and using serial GCD queues to save large chunks of data, since it was faster than having multiple threads accessing the same persistent store, even if they operate on different managed object contexts.
I hope I helped.

Avoiding registered object buildup (memleak) in NSManagedObjectContext

I have a memory-intensive iOS app and I'm working on making sure that memory usage does not build up over time. My app has a "main" context that lives for the lifetime of the app, with other smaller contexts being spawned occasionally for background tasks.
One thing I have noticed is that NSManagedObjects appear to remain registered in the main context long-term and the only way to truly reclaim all the memory associated with pulling the objects from the DB is to call [NSManagedObjectContext reset].
This of course results in a nice drop in memory usage as all the registered objects from recently closed list views are properly ejected from memory, however it is annoying because you have just invalidated every object that was registered in that context that you still have a reference to (i.e. objects that are refered to by views that are still open), and you now need to re-fetch all the these objects from the database to avoid exceptions for accessing an invalidated object.
Is this the only way of flushing out the registered object set from an NSManagedObjectContext, or is there a better way that successfully ejects all the registered objects you no longer have references to, but doesn't invalidate all the NSManagedObjects that are still alive?
NSManagedObjectContext has an internal row cache, and the only way you can clear that out is by resetting the context. If you're actually experiencing memory issues, a few things that may help are:
Managed objects retain their related objects. If you have managed object A that's referenced by a relationship from some other managed object B, then object A will remain in memory even if you've released all references to it. It won't actually be deallocated until object B is deallocated or re-faulted, because it will still be retained by B.
One way of dealing with this (and other memory issues) is by calling refreshObject:mergeChanges: on the MOC for objects you aren't currently using, with the second argument set to NO. That re-faults the object, i.e. makes the object go back to the initial "fault" state, unloading its property values and relationships. With A and B from before, re-faulting B would release the relationship to A. Keep in mind this will lose any unsaved changes on B, so make sure you've saved first if necessary.
If your managed objects contain any kind of large binary data, try moving that data into a separate entity or out of Core Data altogether to avoid loading it into memory when it's not needed.
reset on the MOC is basically the nuclear option when it comes to Core Data memory management. It's extremely effective but as you've found can be very dangerous. It's best avoided unless you already aren't using any objects loaded from the MOC.

Resources