Ben Thompson
Ben Thompson

Reputation: 4833

Collating all core data code into its own class

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]];

}

Upvotes: 1

Views: 276

Answers (2)

jrturton
jrturton

Reputation: 119242

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 = coreDataModel in your app delegate after you create the VC.

Upvotes: 1

I agree that keeping the database code out of as much as possibly is much cleaner, I also use a kind of CoreDataModel singleton from which I can ask for context or other CoreData related classes.

For code that works with entities, I use "mogenerator" to generate data objects from Core Data models.

This tool outputs two sets of classes per entity - one class representing the entity accessors, the other class inheriting from that and representing a class into which you can place all of your Core Data related code.

So for example if you have a Cat entity, you can have things like:

+ (Cat*) newCatWithID:(NSString *)id;
+ (NSArray *) catsWithHairType:(NSInteger)hairType;
- (NSDictionary *) catComponentsInHumanReadableStrings;

You get the idea, each one of those methods can keep the Core Data operations within that class, as opposed to spread throughout your code everywhere. Then other classes only need to look at and use your data objects, without knowing Core Data (except they may have to save but you could ask your shared model to handle that).

Upvotes: 1

Related Questions