Understanding code of autogenerated files

On creating a new application through Xcode, it simplifies the task of the developer by generating several files for us that are required for successful execution of the application. The two important files that are autogenerated by Xcode are application delegate files. The question is what is the usage of application delegate files? The answer is quite simple: there are several important events that happen in the life of an application. The two most important events are launching and termination of the application. The application needs to know when these events happen or are about to happen. The iPhone OS notifies about these events through Application Delegate by calling its appropriate methods. iPhone OS calls the applicationDidFinishLaunching method when it finishes the launch procedure and calls applicationWillTerminate when the application is terminated, so as to close any open files.

Let's have a look at the code of the autogenerated files. We begin with the header file of Application Delegate:

Header file of Application Delegate

The header file of Application Delegate, progAppDelegate.h contains some default code, as shown in the following code listing:

// probAppDelegate.h
// prob
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface probAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
@private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory;
- (void)saveContext;
@end

The preceding file declares instance variables of the NSManagedObjectModel, NSManagedObjectContext, and the NSPersistentStoreCoordinator class. Also, all of the variables including an NSString instance are defined as properties with the two attributes: retain and nonatomic. The retain attribute informs the compiler to retain (keep) the instance variable and not to flush from memory while being used. The nonatomic attribute informs the compiler that when it will be asked to generate the accessor and mutator methods of the outlets (synthesized), it should generate them without any additional code of implementing multithreading. The nonatomic attribute is used for simple applications.

Let us also see the autogenerated code in Application Delegate's implementation file: probAppDelegate.m.

Implementation file of Application Delegate

The implementation file of Application Delegate, progAppDelegate.m, contains some default code, as shown in the following code listing:

// probAppDelegate.m
// prob
#import "probAppDelegate.h"
#import "RootViewController.h"
@implementation probAppDelegate
@synthesize window;
@synthesize navigationController;
- (void)awakeFromNib {
RootViewController *rootViewController = (RootViewController *) [navigationController topViewController];
rootViewController.managedObjectContext = self.managedObjectContext;
}
- (BOOL)application:(UIApplication *) application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions {
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}

In awakeFromNib method, the root view controller of the application is set equal to the top view controller of the navigation controller. In applicationDidFinishLaunching method, the view of the navigation controller is set as a subview of the content view and hence is displayed to the user.

- (void)applicationWillTerminate:(UIApplication *)application {
[self saveContext];
}
- (void)saveContext {
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}

applicationWillTerminate method

The applicationWillTerminate method is invoked just before exiting from the application and is usually used for saving the modifications applied to the managed object via managed object context. That is, the managed object context (containing the modifications applied to the managed object) is saved to the persistent store. The save action method is used for saving the managed object context to the persistent store, that is, the changes made to the managed object context are committed through this method. An error will be displayed if there occurs some problem while saving the managed object context.

- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}

managedObjectContext method

Every application has at least one managed object context. The managed object context maintains the state of the managed object after it is loaded in memory. All modifications that we apply to the managed object are actually applied to the managed object context. It keeps track of all the changes made to the managed object since the last time it was loaded in memory and hence helps in undoing any changes made to the managed object (if required). When we want to commit the modifications made to the managed object, we save the managed object context to the persistent store.

Note

The managed contexts are not thread-safe, which means there are many chances of faults when managed object contexts are shared between threads or are accessed from multiple threads simultaneously. To avoid any conflicts, we need to apply the Locking mechanism. In other words, contexts in general should not be shared between threads. Apple's advice is to use one context per thread and to merge changes.

In the preceding method, a check is made to see if the instance variable, managedObjectContext, already exists or not (nil value means the instance variable does not exist). If the instance variable exists, it is returned, else it is created. In order to deal with persistent store, the managed object context needs a reference to a PersistentStoreCoordinator. Recall that the PersistentStoreCoordinator is the essential middle layer in the stack that helps in storing and retrieving the managed object model from the persistent store (in the form of managed object context). So, to create the managedObjectContext instance variable, we check for a pointer to the NSPersistentStoreCoordinator. If the pointer to PersistentStoreCoordinator exists, we create a new managedObjectContext and after linking it with the pointer to the PersistentStoreCoordinator, return it.

- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"prob" ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}

managedObjectModel method

This method first checks if the instance variable managedObjectModel (of NSManagedObjectModel class) already exists or not (nil value means the instance variable does not exist). If the instance variable exists, it is returned, or else it is created by merging all the data models found in the application bundle. It also means that we can have several data models (created in separate .xcdatamodelfiles) in an application. All the data models (entities and their relationships) contained in different files will be merged (combined) into a single managed object model.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"customersdata.sqlite"];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}

persistentStoreCoordinator method

The NSPersistentStoreCoordinator class is meant for storing and retrieving the managed object model from the persistent store. It also helps in avoiding redundancy if multiple calls are made by different classes on the same file at the same time. The multiple calls are serialized by the NSPersistentStoreCoordinator class to avoid redundancy.

The preceding code first checks whether the instance variable, persistentStoreCoordinator, exists or not. If it exists, it is returned, or else it is created. Because we want to store the names of the customers in the file: customersdata.sqlite, we define a path to the file in the Documents directory of our application's sandbox.

We want the format of the persistent store to be of SQLite type, hence the parameter NSSQLiteStoreType is passed to the method to specify the type of the persistent store. NSSQLiteStoreType is a constant that tells Core Data to use a SQLite database for its persistent store. If we want to store the information in binary format, we may use the constant, NSBinaryStoreType for the persistent store. If anything goes wrong while creating the instance variable persistentStoreCoordinator, an error will be displayed:

- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

applicationDocumentsDirectory method

This method is for finding the location to store the persistent store file. In Xcode, each application has its own sandboxed Documents directory designed for the storage of files. So, we retrieve a list of the cache directories from the SearchPathForDirectoriesInDomains method and write code to find the Documents folder specific to our application.

- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[navigationController release];
[window release];
[super dealloc];
}
@end

The dealloc method is for releasing the memory assigned to different instance variables.

As seen in the previous code we specify the file: customersdata.sqlite for storing the names of the customers in the NSURL statement of the persistentStoreCordinator method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.10.248