I am using Core Data for the first time, and I am a but confused on a few things.
First let me explain the context of my app. It is essentially a virtual planner, like the kind that you had in high school/middle school with the times that classes start/end where kids are supposed to write their homework. I am trying to use core data to save around 11,000 of these period objects and query them to get the periods on a given day.
The problem that I am having is that I initialize my NSManagedObjectContext and NSManagedDocument in my AppDelegate so that the periods are loaded immediately once the app starts. I now want to query those period objects in the Core Data from a different class (DayView). How do I create a reference to the Core Data database from DayView.m so that I can query it? It seems weird to me to [alloc init] an instance of AppDelegate in order to access the property that I have for the NSManagedObjectContext.
Thanks for all of your help and I will be happy to clarify anything in the comments.
Don't do that in your application delegate. It's called the application delegate because it should do exactly those things involved in being the UIApplication delegate. It really shouldn't do any more than kick off the first view controller, if you're not using a storyboard, possibly opt into UI state restoration, and deal with distributing things like push notification tokens that arrive at the delegate.
Factor out your Core Data stuff into its own class. Have everyone else talk via that class. The singleton pattern is a common way to prevent yourself from having to pass the instance of that class all over the place if it's a simple design fact that there'll be only one of them.
The preferred way to do this is to create the NSManagedObjectContext (and it's dependancies) either when it's first needed or at application launch.
The NSManagedObjectContext is then passed to the first view controller, which then passes it on again to subsequent view controllers. This is what the Xcode Core Data templates do, and is the preferred way to do this.
This is covered in the Core Data Programming Guide, Core Data Snippets, and the Core Data Release Notes for MacOS 10.7 and iOS 5. Of those three sources, the release notes document is the most current. From the release notes:
Nested contexts make it more important than ever that you adopt the “pass the baton” approach of accessing a context (by passing a context from one view controller to the next) rather than retrieving it directly from the application delegate.
(And yes, you should be using nested contexts.)
You don't allocate an instance of it; you can access the App Delegate & it properties with
[UIApplication sharedApplication] delegate]
But I would suggest you save yourself some grief and create a data helper class that contains all your core data stuff. It can be initialized in the App Delegate then referenced as needed from there. I use this:
dataHelper = [(AppDelegate *)[[UIApplication sharedApplication] delegate] dataHelper];
Then let dataHelper have all the code you need for core data access.
Related
I just started working with core data in iOS app dev using swift. The first two things that I encountered are: 1. AppDelegate 2. NSManagedObjectContext.
I understand that 'AppDelegate.swift' file is a source file just like the 'ViewController.swift'. But in all the tutorials it was referred as 'something which will be used later'. Perhaps, now is the time to get familiar with it. Could you kindly tell me what exactly it does?
What does an object of type 'NSManagedObjectContext' do? What is its function? Could you please put its function in simpler words?
Thanks in advance.
Have a look at the following figure for visual understanding of Key objects in an iOS app:
Role of AppDelegate:
The app delegate is the heart of your app code. It handles app initialization, state transitions, and many high-level app events. This object is also the only one guaranteed to be present in every app, so it is often used to set up the app’s initial data structures.
AppDelegate is used for the whole app, you can use it to manage the app life cycle, on the other hand, ViewController is used for a single view. you can use it to manage life cycle of a view. One app can have multiple views. but only one AppDelegate.
Role of NSManagedObjectContext:
The NSManagedObjectContext is a fundamental concept of Core Data.It is like transaction in a relational data. You can fetch objects, you can create objects , update and delete them, save them back to the persistent store, etc. Basically for all the core data operations, you will need to interact with NSManagedObjectContext.
UIApplicationDelegate is an interface between device (the iOS system) and your application. You will i.e. handle push notifications in this class
Context is more complicated. Generally all object that comes from CoreData has some context which is responsible for sync all object in this context. So if you fetch object A and in some other point of code you will fetch again this object (lets call it A2) and both are fetched in the same context then A == A2 is always true. But that's just the tip of the iceberg.
I am writing an app that has a form spread across multiple ViewControllers and a main menu with the submit button on it that opens an e-Mail with the text fields data displayed in it, the only problem i have is that the text boxes don't 'remember' what's been written in them when switching between sections of the form. I have had a look through threads regarding persistent data but have found nothing. I want my application to remember what's been entered in the text fields when switching between views so it can populate the e-Mail with the data but then 'forget' the data again when the user minimises the app. Any advice or pieces of code would be much appreciated.
So create a data model singleton and have your view controllers read/write their values from properties of that singleton.
(In viewWillAppear, fetch a pointer to the model singleton and install values from properties of the singleton into your VC's fields. When the user changes a value in a field, have your VC modify the corresponding property of the singleton.
You can write your singleton to listen for the "will enter background" notification and archive it's settings to disk, and make it's init method try to read saved values from disk (or set the values to a defined starting state if they have never been set). You can use NSUserDefaults, NSCoding, or a variety of other approaches for archiving your data.
There are lots of options to persist data. I currently favoring Realm, but previously I've used Core Data, YapDatabase, and even simply serializing objects to disk. Note that if this is your first foray into saving data on iOS, I strongly advise AVOIDING Core Data, as it is very complex and Feature Rich (also, difficult to use correctly until you know it fluently). I recommend you start with serializing objects yourself, then either Realm or YapDatabase.
You should create a singleton NSObject class and keep data in that class ... As singleton objects hold data until the application is terminated.
I'm starting to try and add support for state preservation and restoration to my iOS app, which has a Core Data component to it that I access via a UIManagedDocument.
I'm starting to add the restoration identifiers to my view controllers, and have hooked up the required functions (currently empty) within my AppDelegate, and controllers.
I have an object that could potentially be referenced by multiple view controllers so I plan to try and preserve and restore this within my AppDelegate and just have the relevant view controllers retrieve the object from the AppDelegate. Timing of this could be tricky as the app delegate method didRecodeRestorableState occurs after all the views have already called their own decodeRestorableStateWithCoder methods.
My main problem though is that this shared class as well as multiple ViewControllers all want to have NSManagedObject properties preserved and restored. I hope to be able to use the object's URIRepresentation to facilitate this but the problem I have is my AppDelegate will open my UIManagedDocument within my AppDelegate's willFinishLaunchingWithOptions method. It does this via the UIManagedDocument openWithCompletionHandler method. Due to the threading of this opening the document is successfully opened after all my views and app delegate have already tried to restore their saved state. The AppDelegate does send a notification out once the document is ready for use, so all my view controllers can listen to this notification.
I guess I just wonder is this the best, or even only strategy for dealing with this. My objects will need to hold onto the URIRepresentations that they restore and only once the document (and it's NSManagedObjectContext) is ready try to actually find and set the corresponding NSManagedObjects up that they saved out. As such the restoring is happening a lot later than the calls to perform the restoring would I assume usually perform all their restoring work. I worry whether a controller may potentially appear empty for a brief period of time whilst it waits for the document to open and then get properly initialised.
Is there any purpose in blocking and delaying the opening of my document in this case so yes the app takes longer to open but can at least restore more correctly with all the data required before any views appear. Are there any timers being ran to make sure certain methods don't take too long? Would it be more correct to show a different view whilst we're in this limbo state, not quite sure how to go about this but its the sort of thing you may see with other apps like say the Facebook app which is dependant on a network connection.
I can't seem to find any real explanation of this sort of issue within the documentation so far.
Any help is as always very much appreciated! Cheers
In the end I just implemented notifications from when my UIManagedDocument had finished loading. These were picked up by all controllers that had coredata managed objects it wanted to restore. During restoration I keep hold of the encoded URIs, and later when receiving this UIManagedDocument ready notification I just decoded the URIs to their respective managed objects.
The problem with the shared object that I described I solved by encoded and restoring in one place from my appDelegate and then using another notification out to systems to tell them that this shared object was now fully decoded and available for use.
Not ideal and involved creating quite a lot of hierarchies of methods to ensure all objects were decoded correctly but it works ok.
Sadly since then I've hit a stumbling block where UIDataSourceModelAssociation protocol methods are being called by the OS before my UIManagedDocument has finished opening. Sadly this means that I'm unable to do anything useful. So what i really need to do somehow is defer my app restoration until everything is loaded from a CoreData UIManagedDocument POV. That problem continues...
task details:
I'm developing an app that communicates with 1-30 hardware devices simultaneously, each device has it's own tcp connection.
Therefore I created an entity "hardwareObject" which shall represent some properties of that device, e.g. value1 and value2.
I created a connection handler class which I defined as a transient attribute of my "hardwareObject" entity. On UI changes the core data object is modified and the core data object itself tells it's connection to send changes of value1 or value2.
I want to inform an instance of "hardwareObject" when new data arrived via a delegate method, therefore it's a delegate of it's attribute.
I'm wondering if making a NSManagedObject a delegate of s.th. is a good practice?
Might that cause any problems regarding faulting or other core data related things?
Or should I better create a sharedInstance master connection handler object which takes care of each of the connection handlers and talk to my core data objects only on demand?
That's a totally valid design. NSManagedObjects may be managed by their (managed object) context, but if you retain an NSManagedObject it will remain valid, and you're free to implement any special business logic in that class or make it a delegate. In fact, one of the resounds that Core Data allows you to subclass NSManagedObject is such that you can do these things.
Just make sure to unregister your class as the delegate if you need to delete the object from the context.
It sounds like a bad idea. Delegates need to exist for at least as long as the object they are a delegate for, and you don't have control over the lifecycle of managed objects - this is taken care of by the context.
As you mention in your question, faulting could also be an issue - any state information could disappear at any point, again, out of your control.
In addition, this sounds like quite a serious violation of MVC, if that concerns you.
I have a navigation based application using Core Data and several levels of drill-down navigation. At the last level of the navigation I add records to the managed object store.At each level of navigation I create an array of view controllers for the next UITableView.
My question concerns the placement of the Core Data stack methods which create the managedObjectContext, managedObjectModel and the persistentStoreCoordinator.
Do I create these methods in the highest level view controller that needs to fetch data from the persistentStore and then pass a context object to the lower level viewcontrollers? Do I also need to pass a coordinator?
Many questions seem to point to putting these methods in the App Delegate but then many answers say "Do Not" put them in the app delegate. So where is the best place for these methods and which objects need to be passed to allow all necessary levels to fetch from the data store?
First, some pre-requisites:
If you're building an application that uses Core Data, then you will most probably encounter situations where you will need to have more than one managed object context (MOC) around. You will however need one MOC that will "live" throughout the whole application session. Call that your main MOC (since you'll be accessing it from the main thread only!!).
More rarely and depending on your application, you may also encounter situations where you will need more than one NSPersistentStoreCoordinator. In my answer I will stick to the case where a single coordinator is required. As for your NSManagedObjectModel, that is entirely dependent on your application. Usually, you only need one of those.
To answer your questions:
I suggest having your main MOC be owned by the AppDelegate, since the latter is a singleton that lives for as long as the application lives. You can put the methods for creating/saving the main MOC in the AppDelegate, or delegate these tasks to a utility class. I find the second option a little cleaner, as you can use that utility class to add methods that create other MOCs on the fly, or to get a reference to the main MOC, from any controller in your application. That way, you avoid calling the AppDelegate all the time.
Note also, that if you already have a NSManagedObject in your hands, you can get the reference to the MOC that it's registered with, simply by calling [yourManagedObject managedObjectContext]. Once you have the MOC reference, you can get the associated NSPersistentStoreCoordinator and NSManagedObjectModel references. (This is to answer your question about "passing the coordinator": I prefer working with NSManagedObjects and the NSManagedObjectContext since they are at the top-most level of the abstraction, instead of passing around the coordinator or the model).
Hope this helps!
Apple puts the Core Data stack in the app delegate which works for the majority of cases.
It sounds to me like you are under utilizing Core Data. It sounds like your app design just uses Core Data to persist some data after you've gone down a hierarchy of views that are populated by arrays. Although you can get this work, you lose a lot of the automatic functionality of Core Data.
Core Data is not primarily about saving data. Instead it is an API for creating the model layer in a Model-View-Controller design app. As such, Core Data usually comprises the actual logical "guts" of the application. Apple puts the stack in the app delegate because it is assumed that Core Data will be used throughout the app.
In the standard design, you would use Core Data to populate all your views so you would need Core Data at the top an bottom of any hierarchy.