Core Data error message - ios

I created a Core Data Entity named: "Athlete".
Here is the error that I am getting:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Athlete''
This is the line at where it breaks:
Athlete *detail = [NSEntityDescription insertNewObjectForEntityForName:#"Athlete" inManagedObjectContext:context];
delegate.h
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
delegate.m
-(void)createData{
NSManagedObjectContext *context = [self managedObjectContext];
Athlete *detail = [NSEntityDescription insertNewObjectForEntityForName:#"Athlete" inManagedObjectContext:context];
detail.first = #"Joe";
detail.last = #"Pastrami";
detail.phone = #"(123)456-7891";
NSError *error;
if(![context save:&error]){
NSLog(#"Error :(");
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Athlete" inManagedObjectContext:context];
[request setEntity:entity];
NSArray *arr = [context executeFetchRequest:request error:&error];
for (Athlete *ath in arr){
NSLog(#"Name %#", ath.first);
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self createData];
}

The error says it all: your managedObjectContext is nil.

Have you correctly passed your managedObjectContext object from AppDelegate to your UIViewController? If not, 2 ways to do this:
From AppDelegate (example app with UINavigationController at root):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSManagedObjectContext *context = [self managedObjectContext];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController.navigationController;
YourViewController *yourViewController = (SearchViewController *)navigationController.topViewController;
yourViewController.managedObjectContext = self.managedObjectContext;
...
}
From YourViewController:
#import AppDelegate.h
...
#synthesize managedObjectContext;
- (void)viewDidLoad
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
managedObjectContext = [appDelegate managedObjectContext];
...
}

Related

Coredata Fetched Results Controller save with child NSPrivateQueueConcurrencyType context

I have UICollectionViewController with <NSFetchedResultsControllerDelegate> and CoreData Singleton manager. So when I trying to update some Title of my object I see error.
CollectionViewController.m
#interface CollectionViewController ()<NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext* managedObjectContext;
#implementation CollectionViewController
- (NSManagedObjectContext*) managedObjectContext {
if (!_managedObjectContext) {
_managedObjectContext = [[CoreDataManager sharedManager] managedObjectContext];
}
return _managedObjectContext;
}
-(void)pushTheButton: (UIButton*) sender{
NSIndexPath *indexPath = [self.collectionView indexPathForCell:(PKMapObjectCVCell *)sender.superview.superview];
SomeObjectClass* object = [self.fetchedResultsController objectAtIndexPath:indexPath];
[[CoreDataManager sharedManager] changeValueForObject: object.objectID];
}
CoreDataManager.m
#implementation CoreDataManager
#synthesize mainPrivateManagedObjectContext = _mainPrivateManagedObjectContext;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+(CoreDataManager*) sharedManager{
static CoreDataManager* manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CoreDataManager alloc] init];
});
return manager;
}
- (void) changeValueForObject:(NSManagedObjectID*) myobjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
SomeObjectClass * editableObject = [bgcontext objectWithID:myObjectID];
editableObject.title = #"New Title";
// [bgcontext updatedObjects];
[self saveContextForBGTask:bgcontext];
}
- (void)saveContextForBGTask:(NSManagedObjectContext *)bgTaskContext {
if (bgTaskContext.hasChanges) {
[bgTaskContext performBlockAndWait:^{ //error on this line:
[error] error: Serious application error. Exception was caught during
Core Data change processing. This is usually a bug within an observer
of NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) CoreData: error: Serious application error.
Exception was caught during Core Data change processing. This is
usually a bug within an observer of
NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) 2018-03-21 17:07:42.644646+0400
AppName[17860:3506816] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: 'The left hand side
for an ALL or ANY operator must be either an NSArray or an NSSet.
NSError *error = nil;
[bgTaskContext save:&error];
}];
[self saveDefaultContext:YES]; // Save default context
}
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
_mainPrivateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_mainPrivateManagedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:_mainPrivateManagedObjectContext];
return _managedObjectContext;
}
- (NSManagedObjectContext *)getContextForBGTask {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:_managedObjectContext];
return context;
}
So, what I am doing wrong?
code delete object, is working fine:
- (void) switchObjectLike:(NSManagedObjectID*) mapObjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
PKMapObj * mapObject = [bgcontext objectWithID:mapObjectID];
[bgcontext deleteObject:mapObject];
[self saveContextForBGTask:bgcontext];
}
So, problem was with predicate in NSFetchedResultsController. When some content was updated, NSFetchedResultsController preparing to reload collection view, and before call this method:
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
it was crashed, but never shown error with it. Thanks everybody!

Not able to display results in the console

I made an application for storing data in CD. I want to just simply write the things into the console but I can't get printed on the console. Am I doing something wrong?
Here is my code whole demo application.
Here is my screen shot of Core_Data_Demo_xcdatamodeld
// AppDelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
// AppDelegate.h
-(BOOL)createNewRectangleWithHeight:(NSInteger)heightParam width:(NSInteger)widthParam{
if (heightParam ==0 || widthParam ==0) {
NSLog(#"The height and width must no be 0");
return NO;
}
Rectangle *rect = [NSEntityDescription insertNewObjectForEntityForName:#"Rectangle" inManagedObjectContext:self.managedObjectContext];
if (rect == nil) {
NSLog(#"Failed to create new Rectangle");
return NO;
}
rect.height = [NSNumber numberWithInt:heightParam];
rect.width = [NSNumber numberWithInt:widthParam];
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]) {
return YES;
} else {
NSLog(#"Failed to save new person. Error = %# ",savingError);
}
return YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self createNewRectangleWithHeight:2 width:2];
return YES;
}
You are not able to see any statements because (I suppose) things run correctly.
If you want to retrieve data and print in the console you need to run a different method like printData or whatever you want. This method should set up a NSFetchRequest and execute it against your entity Rectangle.
- (void)printData {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Rectangle"];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
if(error) {
// An error occurred
} else {
// See the results
}
}
Usage
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// [self createNewRectangleWithHeight:2 width:2];
[self printData];
return YES;
}
You should comment the createNew... method otherwise you will see multiple entries (equal to the number of times you've run the application) of Rectangle objects with the same width and height.
The code which you have shown is for adding values using core data, If you do not get any error in the NSError object while you are adding the values then data is successfully added inside the sqlite file.
To check the added values what you can do is use the SqliteManager addon from firefox and open the sqlite file (You can get the sqlite file location using NSHomeDirectory() method for it and then jump to the documents folder).
If you don't want the addon way you can always use NSFetchRequest to pull your data given below is the code for the same
- (NSManagedObjectContext*)getManagedObjectContext{
AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
return appDelegate.managedObjectContext;
}
- (void)fetchdataFromDatabase{
NSManagedObjectContext *appContext = [self getManagedObjectContext];
if(appContext!=nil){
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"YOUR_ENTITY_NAME" inManagedObjectContext:appContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [appContext executeFetchRequest:fetchRequest
error:&error];
if(error!=nil && fetchedObjects.count!=0){
// print your data here
}else{
//Print the error here
}
}
}

Trouble mixing UISegmentedControl with Core Data

I have been searching for the answer for a couple of weaks now but I just can't seem to find it. I have been trying to get a UISegmentedControl's data to save in the Core Data but I can't do it, it keeps showing me an errors and warnings, hope you can help me.
I have something like this:
#import "DetailScoutingViewController.h"
#interface DetailScoutingViewController ()
#property (strong, nonatomic) IBOutlet UITextField *name;
#property (strong, nonatomic) IBOutlet UITextField *number;
#property (strong, nonatomic) IBOutlet UISegmentedControl *considered;
- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;
#property (strong, nonatomic) NSManagedObject *teamData;
#end
#implementation DetailScoutingViewController
#synthesize teamData;
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.teamData) {
[self.name setText:[self.teamData valueForKey:#"name"]];
[self.number setText:[self.teamData valueForKey:#"number"]];
[self.considered setSelectedSegmentIndex:[self.teamData valueForKey:#"considered"]];
}
}
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.teamData) {
// Update existing device
[self.teamData setValue:self.name.text forKey:#"name"];
[self.teamData setValue:self.number.text forKey:#"number"];
[self.teamData setValue:self.considered.selectedSegmentIndex forKey:#"considered"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Teams" inManagedObjectContext:context];
[newDevice setValue:self.name.text forKey:#"name"];
[newDevice setValue:self.number.text forKey:#"number"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self.navigationController popViewControllerAnimated:YES];
}
- (IBAction)cancel:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
The UITextField's data saves without a problem, the only problem I have is the UISegmentedControl. What should I do?
[self.teamData valueForKey:#"considered"]
This returns what is likely to be an NSNumber instance, but setSelectedSegmentIndex: expects an NSInteger so you should be using:
[self.considered setSelectedSegmentIndex:[[self.teamData valueForKey:#"considered"] integerValue]];
You also need to change the corresponding save code to:
[self.teamData setValue:[NSNumber numberWithInteger:self.considered.selectedSegmentIndex] forKey:#"considered"];
This bit of code is not helping:
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
change to:
if ([delegate respondsToSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
At some point in some other controller you should be setting ...teamData = .... If you aren't, then your controller will always be creating a new Teams managed object and inserting it into the data store. In this case, you don't set the self.considered.selectedSegmentIndex so you will never store it. It's only ever stored when you already have a Teams object.

managedObjectContext unrecognized selector sent to instance

I am following a tutorial to develop an iOS app. I am using core data. The first view of the app is RootViewController. All Core Data stack is on the AppDelegate file. This is the part of the code from AppDelegate.m that makes the call to the RootViewController file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Fetch the data to see if we ought to pre-populate
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self loadFavoriteThingsData];
RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
[rootViewController setManagedObjectContext:[self managedObjectContext]];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
return YES;
}
Now, in another part of the app I need to open a new view Controller that is a duplicate of RootViewController, called DoneViewController, but using other NSPredicates to show other core data objects.
In RootViewController there is a button to open the MenuViewController file, from there I try to open DoneViewController using following method:
- (IBAction)doneToDoaction:(id)sender {
DoneViewController *viewController = [[DoneViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
but an exception is fired:
[MenuViewController managedObjectContext]: unrecognized selector sent to instance 0x145a0c00
2013-12-26 22:58:23.688 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MenuViewController managedObjectContext]: unrecognized selector sent to instance
I guess I have to pass the managedObjectContext from RootViewController to MenuViewController and then from MenuViewController to DoneViewController, but I don't know how to do it.
This is due to that you are not using NSObject class. For this you have to implement NSObject in you AppDelegate.h.Like this..
#interface AppDelegate : UIResponder <UIApplicationDelegate,NSObject>{
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
}
and also add the properties.
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSString *)applicationDocumentsDirectory;
Also add code in AppDelegate.m file...
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil] ;
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"<Project Name>.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error])
{
/*Error for store creation should be handled in here*/
}
return persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
This works for me 100%. Hope so that it work for you.
There are few solutions to do what you want.
The first is to expose the context from the application delegate as #Gyanendra commented. The second is to pass the context from controller to controller. For further references I really suggest to read PASSING AROUND A NSMANAGEDOBJECTCONTEXT ON IOS by Marcus Zarra.
Anyway, I would prefer the second solution. Passing around the context or grabbing by an instance of NSManagedObject. Based on the latter each NSManagedObjectInstance has a reference to the context has been registered in.
[managedObjectInstance managedObjectContext];
These solutions prevent to have a rigid application and avoid to pollute the application delegate.
In your case, you could just follow this approach. From RootViewController pass the context to MenuViewController and then, from the latter, pass it to DoneViewController. How?
Simple enough. Just expose properties like for the controller you are interested in (MenuViewController and DoneViewController in this case).
#property (nonatomic, strong) NSManagedObjectContext* mainContext;
that can be set as
// from RootViewController
menuViewController.mainContext = [self managedObjectContext];

Trouble adding Core Data to a Storyboard App

I am having trouble adding a Core Data functionality to my app.
I cannot understand why managedObjectContext is always nil (even in my AppDelegate). I know that I should be passing it from the model, but and not sure how to do this.
I get the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Goal''
g4tappDelegate.h
#import <UIKit/UIKit.h>
#import "Goal.h"
#class g4tPopPageViewController;
#interface g4tAppDelegate : UIResponder <UIApplicationDelegate> {
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
UIWindow *window;
}
- (NSManagedObjectContext *)managedObjectContext;
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) g4tPopPageViewController *PopPageViewController;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#end
g4tappDelegate.m
#import "g4tAppDelegate.h"
#import "g4tPopPageViewController.h"
#import "Goal.h"
#implementation g4tAppDelegate
NSManagedObjectContext *managedObjectContext;
#synthesize PopPageViewController;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSManagedObject *newGoal;
//ERROR HERE
newGoal = [NSEntityDescription
insertNewObjectForEntityForName:#"Goal"
inManagedObjectContext:_managedObjectContext];
PopPageViewController.managedObjectContext = self.managedObjectContext;
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController* vc = [sb instantiateViewControllerWithIdentifier:#"AddGoal"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
[self.window setRootViewController:navigationController];
[self.window makeKeyAndVisible];
// Override point for customization after application launch.
return YES;
}
Initialize your context first. Pass the context to the viewController instance first after creating it. Either you are missing some implementation or you didn't post it here.
Also, correct your property
#property (strong, nonatomic) PopPageViewController *g4tPopPageViewController;
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"YourStore.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
// Then pass it to your other controller from your viewDidLoad
vc.managedObjectContext = _managedObjectContext;

Resources