I'm working on a Core Data iPhone app that pulls remote resources from the web into NSManagedObjects and saves them locally.
I want the user to be able to designate which of these objects should be saved. This means that some will be saved, but many should be deleted. However, I might want to save and delete at different times - I'd prefer to save designated objects immediately (in case the app crashes), but still keep around the other objects because they're hanging out in table views and such.
One approach I can think of is to have a different persistent store - one for stuff that will be saved, one for stuff that won't; this way I can save the "should be saved" store at any time. However, I would much prefer to keep objects of the same type in the same domain.
Another approach would be to just save at the very end - negating any ability to recover from a crash. But saving at the end would allow me to parse out any objects that weren't designated "should save".
And that's really what I want - a "shouldSave" method in the NSManagedObject class, or at least a save method that I could fire at select objects. But as far as I can tell, neither of those exist.
So, if anyone has any other suggestions, please let me know! It would be greatly appreciated.
CoreData is not for object serialization, it is an object graph serialization. That is an important distinction. Once you have an NSManagedObject it is associated with a context, and CoreData handles saves at context level since that is the only way it guarantee any sort of object graph consistency. In other words, you can't save individual objects because if they have relationships with other objects you would need to also save those objects and it quickly cascades out to the whole graph.
You seem to be worried about crash recovery. If the app crashed and the user relaunched it would they expect to see just the items they saved, or everything that was on the screen before they crashed? If it is the former you should just delete them at save time and remove them from the users view (with some animation), if it is the later you should commit out everything, and potentially delete the objects you are not interested in at another time.
Related
Recently, I'm working with a timetable app in iOS, and i get trouble with Core Data.
My app has a main user interface kind of like the original calendar app created by Apple, and i save all my events data in the Core Data database.
I create a UIManagedDocument in order to fetch data from database by using its NSManagedObjectContext, and everything works just fine.
However, i need to use the NSManagedObjectContext to fetch data several times in several different view controllers during the runtime. And every time i do this, i need to reopen the UIManagedDocument, but open the document take too much time(it may take 2 seconds or even more, i have to display a spinner in view).
So here are my questions:
What's the right way to open a managedDocument?(I mean like open it during the lunch image time?)
Is there a way to only open the managedDocument once and keep it open during runtime?(So i can use its context all the time)
Does data store in the managedDocument i create?(I found that if i delete the document, data was gone)
Thanks.
You will get lots of different opinions on how to do this but basically you should only have to open the document once. This is done by some object that does the work and stores it so it can return it again when asked by a different view controller.
Many people create singleton's for this or put it in the App Delegate. I have implemented a protocol that lets me put it where ever it is convenient for a particular application without my other code having to know anything about the object that returns the information. As long as it responds to the protocol it can be the App Delegate, a singleton class, or any other object type.
See importing AppDelegate
The protocol that I put in the above example just returns information about where the database is. In my actual implementation I have an openDatabase method with a call back to let me know when it is done plus automatic initialization and updating methods.
You can also improve your performance by having the open operation happen off the main thread. This keeps your UI responsive but does not show the data any faster and you have to be carefull about managed object contexts and the threads they are in.
Good luck...
I need to save my objects in permanent memory. The option I use right now is that i save my objects in the NSUserDefaults before my app quits and I retrieve them when my app starts running. This approach is not very convenient since I may lose important data in case the application crashes. Is there any way to store my objects, but when a property of an object changes, then this change is saved in the disk automatically? Except for that, there is a danger to mess the objects in ram and the objects in the disk using that architecture.
For example
-> Load objects from memory
-> [object1 setValue:#"5"]
-> Application crashes
After the crash, when the user opens the application, the value #"5" will not be available because I never saved the data.
Is there any alternative so as to make by code more safe and maintainable? CoreData is a good option for this problem , or is it an overhead?
If you need to save data, CoreData is the best. You can save after every change if you need to.
If saving info is so important you might want to figure out what could cause/is causing your application to crash and fix that. No matter how good a solution is if your app is going to randomly crash you'll probably lose some data.
It is really not the best of option to save data instantly when a value changes. It's way too expensive for app performance. You must continue using NSUserDefaults to store the values when app is force closed or entered in background.
Your app is designed by you. It MUST not crash but even if it does, don't worry. Anamolies cannot really be handled.
I'm trying to make my first application using Objective C + Core Data, but I'm not sure it's the correct way, as it feels really weird to me.
I have only one data context, which I create at launch time, in the Application Delegate. This data context is used for all the operations (read, write). In another environment (C# and LINQ for example), I try to make these operations as unitary as possible. Here it seems I just have to create the data context once, and work with it without closing it ever (except when the application exits).
I also have an asynchronous operation in which I update this data. Of course, it uses the same data context again. It works, but doesn't feel right.
My Application Delegate keeps a NSArray of the objects contained in Core Data. I use this same NSArray in all my views.
I would actually naturally close the data context once I got all the objects I require, but... aren't the objects always attached to the data context? If I close or release the data context, all these objects will get releases as well, right?
As you can notice, there is something I'm missing here :) Thanks for your help.
The NSManagedObjectContext to which you refer is more of a "scratchpad" than a database connection. Objects are created, amended, destroyed in this working area, and only persisted ("written to the database" if you prefer) when you tell the MOC to save state. You can (and should) init and release MOCs if you are working in separate threads, but the App Delegate makes a MOC available so that all code executing on the main thread can use the same context. This is both convenient, and saves you from having to ensure that multiple MOCs are kept in sync with each other.
By keeping an NSArray of Core Data objects, you are in effect duplicating its functionality. Is there any reason for not working with an NSSet of Core Data objects provided by the MOC?
If you are working asynchronously, then you should not be sharing an NSManagedObjectContext object across threads, as they are not thread-safe. Instead, create one for each thread, but set them to use same NSPersistentStoreCoordinator. This will serialise their access to the persisted data, but you'll need to use notifications to make them each aware of the others changes.
There is a good tutorial/description on how to use Core Data on multiple threads here:
http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/
1) CORE DATA AND THREADS, WITHOUT THE HEADACHE
http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/
2) Concurrency with Core Data
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html
3) Multi-Context CoreData
http://www.cocoanetics.com/2012/07/multi-context-coredata/
I'm diving into iOS programming and am using Core Data in my app to persist the game data, however, I'm wondering if my approach is the wrong way to use Core Data. I have three tables in my DB, with the first two having a one-to-many relationship with the another table (i.e. UserProfile -->> Puzzle Packs -->> Puzzles).
The approach I'm taking to use and persist the data is simple, retrieve an instance of a UserProfile using a NSFetchedResultsController and store the UserProfile object as an instance var in my App Delegate. Then I use that UserProfile object throughout the rest of the code to access and modify the state of the puzzle packs and puzzles (representing the user's progress in the game) and whenever I make a change to the objects, I just call the NSManagedObjectContext's save method to update the DB, which is is also stored in the App Delegate.
My question is, should I be fetching data from the DB anytime I need to access or modify it or is my current approach, of fetching the top object once and calling the save method often, the correct way to use Core Data?
Thanks in advance for your wisdom! I apologize if my question is odd, I'm still a noob.
As long as you're only ever working with these objects with a single NSManagedObjectContext (ie, you never have to merge changes between contexts) then I don't see a problem with fetching once, and saving as needed.
That said, the moment you work with multiple contexts (for example, using NSOperation/NSOperationQueue or other multi-threading techniques, which require separate contexts), you'll want to make sure you merge changes and update other contexts so changes from one thread don't clobber something on another.
So, there have been several posts here about importing and saving data from an external data source into Core Data. Apple documents a reasonable pattern for this: "import and save on background thread, merge saved objects to main thread." All fine and good.
I have a related but different problem: the user is modifying data in the UI and main thread, and thus modifies state of some objects in the managed object context (MOC). I would like to save these changes from time to time. What is a good way to do that?
Now, you could say that I could do the same: create a background thread with its own MOC and pass the changed objectID-s there. The catch-22 for me with this is that an object's ID changes when it is saved, and I cannot guarantee the order of things happening. I may end up passing a different objectID into the background thread for the same object, based on whether the object has been previously saved or not, and I don't know if Core Data can resolve this and see that different objectID-s are pointing to the same object and not create duplicates for me. (I could test this, but I'm lazywebbing with this question first.)
One thought I had: I could always do MOC saves on a background thread, and queue them up with operationqueue, so that there is always only one save in progress. I would not create a new MOC, I would just use the same MOC as in main thread. Now, this is not thread safe and when someone modifies the MOC in main thread while it is being saved in background thread, the results will probably be catastrophic. But, minus the thread safety, you can see what kind of solution I'd wish for.
To be clear, the problem I need to fix is that if I just do the save in main thread, it blocks the UI for an unacceptably long period of time, I want to move the save to background thread.
So, questions:
what about the reasoning of an object ID changing during saving, and Core Data being able to resolve them to the same object? Would this be the right way of addressing this problem?
any other good ways of doing this?
Simply put, you can't move the save to the background thread. Changes are relative to the NSManagedObjectContext and therefore are invisible to a NSManagedObjectContext on another thread.
I would suggest profiling your saves to find out why they are taking so long. Perhaps make them more frequently or find out what else might be causing the performance issue.
You are using a SQLite store right?
UPDATE
If you are using Binary it is definitely going to be an issue as I believe I mentioned to you before. Binary must be loaded 100% into memory and therefore must also be written 100% out to disk.
It may not solve all of your troubles, but there is a method -[NSManagedObjectContext obtainPermanentIDsForObjects:error:] that you can use to obtain the permanent ID for a managed object prior to saving it to the store. So that should be helpful in any synchronization you end up doing.