I have started creating an app which uses a core data stack at the back end. It has various entities within the stack (3 specifically) each of which is accessible by a different table view controller. So, for example, I have a ‘Client’ entity which is accessible by a table view controller. Once a client is selected, a new table view controller is called which displays the records in the ‘Cars’ entity etc…
At the moment, I have followed Apple’s suggestion of passing the ‘managedObjectContext’ down the chain (so to speak) that was created in the AppDelegate. This does indeed work but it means that all of my code which accesses, adds and deletes managedObjects in the stack is integrated in all of my view controllers.
I would have thought it is cleaner (and a better implementation of MVC) to create a ‘CoreDataModel’ class which handles all the interactions with my stack and each viewcontroller can call it as necessary.
Firstly, does this seem sensible/achievable?
Secondly, in my implementation, I have kept all the core data setup code in the AppDelegate and assigned the managedObjectContext to a new instance of my CoreDataModel class. However, in my first viewcontroller I call an instance method of my CoreDataModel class called (NSMutableArray *)retrieveClientList{}. I have set up a little NSLog report when the method is called correctly but this doesnt seem to be getting invoked.
As a help, I have pasted the code from my custom class, as well as the AppDelegate and the first viewcontroller. [There is a rootviewcontroller before the first tableviewcontroller which is just a main menu which i haven’t pasted here as I don’t think it matters]
Any pointers, greatly appreciated…
This is the implementation of my custom CoreDataModel class…
@implementation CoreDataModel
@synthesize managedObjectContext;
-(NSMutableArray *)retrieveClientList {
// Create fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if(mutableFetchResults == nil) {
// Handle the error
}
NSLog(@"Got here!");
return mutableFetchResults;
}
@end
This is the implementation of my AppDelegate…
@implementation iPTAppDelegate
@synthesize window;
@synthesize navigationController;
@synthesize managedObjectContext;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Create new CoreDataModel object
CoreDataModel *coreDataModel = [[CoreDataModel alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
//Handle the error
}
//Pass the managed object context to the new CoreDataModel object
coreDataModel.managedObjectContext = context;
//Set the navigation controller as the window's root view controller and display
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
[coreDataModel release];
[rootViewController release];
[aNavigationController release];
return YES;
}
And finally, this is my first viewcontroller…
#import "ClientListViewController.h"
#import "ClientViewController.h"
#import "CoreDataModel.h"
@implementation ClientListViewController
@synthesize clientsArray;
@synthesize coreDataModel;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Set the title
self.title=@"Clients";
// Add the + button
// self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editMode)] autorelease];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(callAddClientViewController)] autorelease];
[self populateTable];
}
-(void)populateTable {
NSLog(@"Called here");
[self setClientsArray:[coreDataModel retrieveClientList]];
}
One comment on the design, I think these things are more usually implemented as singletons (see lots of examples on here for how to create one).
At the moment, yours is not working because you aren’t passing the core data model object to your view controller. I’d expect to see
rootViewController.coreDataModel = coreDataModelin your app delegate after you create the VC.