What is an the function of AppDelegate and Context in swift? - ios

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.

Related

Initialization methods for PFObject Subclass Objects that are Generated by Parse

This is tagged with iOS, but I'm sure it could be useful for the other Parse SDKs as well. As you may know, Parse added the ability to create native PFObject subclasses to the iOS SDK not too long ago. This is a great addition for a number of reasons. Firstly, it allows compiler to check your code by creating dynamic properties for object attributes:
myObject[#"myAttribute"] is converted to myObject.myAttribute
Secondly, and more important to this question, custom subclasses can have added functionality. For example, say I have created an alarm app that stores Alarm objects on the Parse cloud. In my custom subclass, I can override the + (instancetype)object, - (void)saveEventually, and - (void)deleteEventually methods so that the alarm object can schedule/update/remove a UILocalNotification for itself upon creation, modification, or deletion.
Here's where things get complicated and my actual question comes in. Say a user creates an alarm on one device (which uploads it to the cloud), and then syncs it automatically to another device. The second device obviously updates it's contents in the background with PFQuery's - (BFTask *)findObjectsInBackground and then calls - (BFTask *)fetchIfNecessaryInBackground on each object to ensure that all of its substance is on the device. My question is: What method(s), if any, gets called when a PFObject subclass is found/fetched from the Parse cloud database? For that matter, what about objects initialized from the local datastore?
Like I mentioned, overriding various methods works perfectly for objects that are created and managed on the device, but I am baffled as to how one would run custom code from within a new object that just arrived in memory from the local or remote datastore. Any thoughts or suggestions on how to handle this would be much appreciated. The Parse documentation does not cover such a case, so it may not even be best practice, but it seems to me that it should be. Anyway, thank you for your time and your insights.
As for most subclasses of NSObject, the way to go is probably to override the -init method.
However, as you mentioned in your last paragraph, such practice is undocumented and you should probably avoid it. The way PFObjects work makes it possible to have multiple instances of the same object in memory (multiple PFObjects with the same objectId). And you do not control when or why these objects are created, so relying on code executed when they are initialized is probably a bad idea. If you have been using Core Data, note that Parse really handles things in a different way, so the best practices are different.
For example, I'm not saying this is the case, but what if a copy of each object is created before it is saved ? Of what if the object is created twice when making a query with the 'cache then network' policy ? Even if you make it work, you would still end up with something that could break with every update of the Framework.
I think you should bundle you initialization code in a method of your own that you would call yourself on objects when you receive them from a query or from the local datastore. Overriding is a good design and practice in object oriented programming, but there are some exceptions and I think this is one of them.

State preservation and restoration strategies with Core Data objects in a UIManagedDocument

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...

Access Core Data from multiple classes

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.

From UIManagedDocument to traditional Core Data stack

I created a new App using UIManagedDocument. While on my devices everything is fine, I got a lot of bad ratings, because there are problems on other devices :(
After a lot of reading and testing, I decided to go back to the traditional Core Data stack.
But what is the best way to do this with an app, that is already in the app store?
How can I build this update? What should I take care of?
Thanks,
Stefan
I think you may be better off to determine your issues with UIManagedDocument and resolve them.
However, if you want to go to plain MOC, you only have a few things to worry about. The biggest is that the UIMD stores things in a file package, and depending on your options you may have to worry about change logs.
In the end, if you want a single sqlite file, and you want to reduce the possibility of confusion, you have a class that simply opens your UIManagedDocument, and fetches each object, then replicates it in the single sqlite file for your new MOC.
Now, you should not need a different object model, so you should not have any migration issues.
Then, just delete the file package that holds the UIManagedDocument, and only use your single file sqlite store.
Basically, on startup, you try to open the UIManagedDocument. If it opens, load every object and copy it into the new database. Then delete it.
From then, you should be good to go.
Note, however, that you may now experience some UI delays because all the database IO is happening on the main UI thread. To work around this, you may need to use a separate MOC, and coordinate changes via the normal COreData notification mechanisms. There are tons of documents, examples, and tutorials on that.
EDIT
Thanks for your answer. My problem with these issues is, that I'm not
able to reproduce them. All my Devices are working fine. But I got a
lot mails, about problems like this: - duplicate entries - no data
after stoping and restarting the app - some say, that the app works
fine for some days and stops working(no new data). These are all
strange things, that don't happen on my devices. So for me the best
way is to go back to plain MOC. My DB doesn't hold many user generated
data, all the data is loaded from a webservice, so it's no problem to
delete the data and start of using a new DB. – Urkman
Duplicate entries. That one sounds like the bug related to temporary/permanent IDs. There are lots of posts about that. Here is one: Core Data could not fullfil fault for object after obtainPermanantIDs
Not saving. Sounds like you are not using the right API for UIManagedDocument. You need to make sure to not save the MOC directly, and either use an undo manager or call updateChangeCount: to notify UIManagedDocument that it has dirty data that you want to be saved. Again, lots of posts about that as well. Search for updateChangeCount.
However, you know your app best, and it may just be better and easier to use plain Core Data.
Remember, if you are doing lots of imports from the web, to use a separate MOC, and have your main MOC watch for DidSave notifications to update itself with the newly imported data.
UIManagedDocument is a special kind of document, an UIDocument subclass, that stores its data using Core Data Framework. So it combines the power of document architecture and core data capabilities.
You can read more about document based architecture from Document Based App Programming Guide for iOS and I recommend WWDC2011 Storing Documents in iCloud using iOS5 session video. I also recommend Stanford CS193P: iPad and iPhone App Development (Fall 2011) Lecture 13.
What is created when you call saveToURL:forSaveOperation:completionHandler: is an implementation detail of UIManagedDocument and UIDocument and you should not really worry or depend on it. However in current implementation a folder containing an sqlite database file is being created.
No. All entities will be contained in a single database file also more generally called: a persistent store. It is possible to use more than one persistent store, but those are more advanced use cases and UIManagedDocument currently uses one.
UIManagedDocument's context refers to a NSManagedObjectContext from underlying Core Data Framework. UIManagedDocument actually operates two of those in parallel to spin off IO operations to a background thread. When it comes to the nature of a context itself here's a quote from Core Data Programming Guide:
You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.
But it really is a good idea to take a look at the lectures and other material I posted above to get a general picture of the technologies used and their potential value to you as a developer in different situations.

How do I (should I?) pass the context between UITableViews when using Core Data in a navigation based application?

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.

Resources