Reputation: 1233
I am very new to Core Data and have been trying to following many tutorials, but most of them put all of the Core Data methods into AppDelegate. I have read that it is better to stay away from AppDelegate and use a custom Data Model class to manage these methods.
I have created a custom class to manage all of my data named MyDataModel
. I implemented the boiler plate Core Data code. In one of my view controllers I have a simple method to implement some data using Core Data:
- (void)getProfile {
/*
* getProfile
*/
NSLog(@"%@", _Model.managedObjectContext);
Users *user = (Users *)[NSEntityDescription insertNewObjectForEntityForName:@"Users" inManagedObjectContext:_Model.managedObjectContext];
// Set Data
[user setValue:@"John" forKey:@"fname"];
[user setValue:@"Smith" forKey:@"lname"];
NSError *error;
[_Model.managedObjectContext save:&error];
}
The code from the header file:
#import <UIKit/UIKit.h>
#import "Users.h"
#import <CoreData/CoreData.h>
#import "DataModel.h"
@interface ProfileViewController : UIViewController
// CoreData Related
@property (strong, nonatomic) DataModel *Model;
// Instance Methods
- (void)updateProfileData;
// Core Data Method
- (void)getProfile;
@end
This method is called in the view controller's viewDidLoad
method. When I run this, I get the following error:
'+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Users''
I have found a similar question here on StackOverflow that may help, but I still don't understand what the solution actually is.
'+entityForName: nil is not a legal NSManagedObjectContext parameter - Core Data
The stated solution from that thread was that he passed the context to the ViewController. How is this accomplished? I already thought I was doing that.
EDIT: DataModel.h
:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Workouts.h"
#import "sqlite3.h"
@interface DataModel : NSObject {
sqlite3 *Database;
}
@property (nonatomic, strong) Workouts *currentWorkout;
// Core Data Properties
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *storeCoordinator;
+ (DataModel *)sharedInstance;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end
DataModel.m
:
#import "DataModel.h"
@implementation DataModel
#pragma mark - Core Data
+ (DataModel *)sharedInstance {
static DataModel *sharedModel = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedModel = [[DataModel alloc] init];
//sharedInstance.storeCoordinator = [sharedInstance storeCoordinator];
//sharedInstance.managedObjectContext = [sharedInstance managedObjectContext];
});
return sharedModel;
}
- (void)saveContext {
NSError *error = nil;
if (_managedObjectContext != nil) {
if ([_managedObjectContext hasChanges] && ![_managedObjectContext save:&error]) {
NSLog(@"error: %@", error.userInfo);
}
}
}
#pragma mark - Core Data Stack
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self storeCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_storeCoordinator != nil) {
return _storeCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"model.sqlite"];
NSError *error = nil;
_storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
if (![_storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
return _storeCoordinator;
}
#pragma mark Application's Documents Directory
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end
UPDATE: I realize the reason why the objects were (null)
. I was trying to call the sharedInstance
singleton method and they were not calling correctly. The getter was being called and would throw into a loop that would keep calling the getter. I correctly used the synthesized variables _managedObjectContext
and _storeCoordinator
. The objects now appropriately allocate memory and return the reference. Thanks for the help everyone.
Upvotes: 2
Views: 5313
Reputation: 75058
Dumb question: Your model is in fact named DataModel?
Upvotes: 1
Reputation: 150585
There isn't anything wrong with the Core Data Stack being created in the Application Delegate. Where have you read that this is the case.
It's certainly considered bad design to be calling down to the Application Delegate to get the managed object context, but what most people do is to pass a reference to the managed object context from the Application Delegate to the other view controllers that use it.
Upvotes: 4