Reputation: 970
What are the best practices on where to update my Core Data?
The first guy who worked on this project I'm working right now created all the Core Data related functions inside the ViewController, but I wanted to declare them inside the model classes (NSManagedObject subclass) to separate concerns.
The main function is a AFNetworking postPath that calls a web service and returns an array of objects to add/edit/delete. What I did was create a class method and do this AFNetwork call inside it:
+ (void)updateEbooksListWithSuccessBlock:(void (^)())successBlock andFailureBlock:(void (^)())failureBlock {
NSURL *url = urlSchema (urlWebServices, @"");
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSString *postPath = [NSString stringWithFormat:@"ws-ebooks-lista.php"];
[httpClient postPath:postPath parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([operation isKindOfClass:[AFHTTPRequestOperation class]]) {
NSDictionary *result = [[responseObject objectFromJSONData] retain];
bool success = statusDoRetornoDoWebService(result); //Function that checks if the return was successful
//Configura o Core Data
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *localManagedObjectContext = [[NSManagedObjectContext alloc] init];
[localManagedObjectContext setParentContext:[(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Ebooks" inManagedObjectContext:localManagedObjectContext];
NSPredicate *filterPredicate;
[request setEntity:entity];
if (success) {
NSArray *ebookInfos = [result objectForKey:@"saida"];
Ebooks *ebook;
NSManagedObject *objectInsert;
for (NSDictionary* ebookInfo in ebookInfos) {
filterPredicate = [NSPredicate predicateWithFormat:@"ebooks_id == %@",[ebookInfo valueForKey:@"id_ebook"]];
[request setPredicate:filterPredicate];
ebook = [[localManagedObjectContext executeFetchRequest:request error:&error] lastObject];
objectInsert = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:localManagedObjectContext];
if (ebook) {
if (![[ebookInfo valueForKey:@"excluido"] isEmpty]) {
//Delete Ebook
} else {
//Update Ebook
}
} else {
//Add Ebook
}
if (![localManagedObjectContext save:&error]) {
//Log Error
}
[objectInsert release];
}
}
[request release];
[localManagedObjectContext release];
}
[successBlock invoke];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//Failure
[failureBlock invoke];
}];}
And it works fine while the app is running, but if I close it (through Xcode) and open it again, the changes aren't saved. I tried not using the "parent context" way and just using the AppDelegate managed object context (since AFNetworking callbacks always runs on the main queue) but no success: the data is not persisted. Why is that? Am I doing something wrong? Is it bad practice? Should I leave everything in the View Controller the way it was?
Thanks!
Upvotes: 0
Views: 389
Reputation: 14549
ugh... what I would do is make very naked NSManagedObject
subclasses... then extend them with categories, that way when you regenerate your classes from the updated model you don't have to try to merge in all of your custom logic.
also the custom logic belongs in the model, the model contains the category or class extension.
so take that crap out of the View Controllers and put it in an easily maintainable category or several categories if it is warranted.
Upvotes: 1
Reputation: 80265
I think it is a bad idea to have too much logic that ultimately relates to your data model into your entity classes. These tasks simply do not belong there. The entity classes should focus only on what they encapsulate: the entity instances themselves.
To illustrate: think of a class that represents a number (like NSNumber
). It think it is not convenient to extend it to give you, say, an array of all even numbers within a certain limits, or the nth member of the Fibonacci series. It seems unsound to have a number class be responsible for saving itself to a file, or retrieving information from the web.
For these and similar reasons, I believe the fetching and saving of Core Data entities belongs into controllers, not entity classes. Remember, one of the basic ideas behind the MVC (model-view-controller) pattern is that the controller manipulates the model or asks it for information, not that the model manipulates itself.
I speculate that your troubles are derived mainly from not separating the various functional aspects of your application sufficiently (data model, persistence, network operations, user interactions).
Upvotes: 3