iOS: CoreData save and search NSEntityDescription or kSetAttrDescription - ios

Im new to Objective-C and CoreData and want to learn it and im trying in Xcode 5, im trying to make this tutorial.
I have followed it with some other CoreData table name, but i get some errors with my "ViewController.m" and dont know what to changes, i can see it recomment to changes "NSEntityDescription" to "kSetAttrDescription" but dont know if thats right or wrong to do, hope someone can tell mewhat to do - so i know it next time.
Error issues
Error Descriptions
My ViewController.m code.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Save data as CoreData, to CoreData Table "Kunder" field "navn", "adresse", "alder" from textfield _name.text, _adress.text, _age.text.
- (IBAction)saveData:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newContact;
newContact = [NSEntityDescription insertNewObjectForEntityForName:#"Kunder" inManagedObjectContext:context];
[newContact setValue: _name.text forKey:#"navn"];
[newContact setValue: _adress.text forKey:#"adresse"];
[newContact setValue: _age.text forKey:#"alder"];
//if textfield empty, then error else save and show label message "Kunde Gemt".
_name.text = #"";
_adress.text = #"";
_age.text = #"";
NSError *error;
[context save:&error];
_status.text = #"Kunde Gemt";
}
//Find-search for user by name.
- (IBAction)findKunde:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Kunder" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred =
[NSPredicate predicateWithFormat:#"(navn = %#)", _name.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
//if no user then error, else take name match and get "adresse" and "alder" from CoreData and show it in the text fields _adress.text and _age.text and show matche count in status label.
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
_status.text = #"Ingen fundet";
} else {
matches = objects[0];
_adress.text = [matches valueForKey:#"adresse"];
_age.text = [matches valueForKey:#"alder"];
_status.text = [NSString stringWithFormat: #"%lu antal fundet", (unsigned long)[objects count]];
}
}
#end
My ViewController.h page (no error)
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *name;
#property (strong, nonatomic) IBOutlet UITextField *adress;
#property (strong, nonatomic) IBOutlet UITextField *age;
#property (strong, nonatomic) IBOutlet UILabel *status;
- (IBAction)saveData:(id)sender;
- (IBAction)findKunde:(id)sender;
#end
My AppDelegate.m file
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
....
#end
UPDATE
When adding text to the fields and hit save, i don get a "Save ok" message it jump to xcode and show me this.

Is seems that you forgot to import <CoreData/CoreData.h>.
You can add the import to your precompiled header (...-Prefix.pch) file
which would look similar to this:
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> // <-- Add this !!
#endif
You might also have to add the "CoreData.framework" to the "Link Binary With Libraries"
section of the targets "Build Phases".

Related

How to pass database from AppDelegate to ViewController

I don't know why this code error.
Please help.
I read some articles and I think the problem is about context.
What Should I do?
This program is about shows data in coredata to label in viewcontroller.
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.m
#import "AppDelegate.h"
#import "Test.h"
#import "ViewController.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSManagedObjectContext *context = [self managedObjectContext];
Test *t = [NSEntityDescription insertNewObjectForEntityForName:#"Test"
inManagedObjectContext:context];
t.name = #"please";
return YES;}
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (nonatomic,strong) NSArray *temp;
#property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;
#end
ViewController.m
#import "ViewController.h"
#import "Test.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize managedObjectContext;
#synthesize temp;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Test"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.temp = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
for(Test *info in temp){
_label.text = info.name;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Test.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Test : NSManagedObject
#property (nonatomic, retain) NSString * name;
#end
Test.m
#import "Test.h"
#implementation Test
#dynamic name;
#end
I don't know why this code error.
Please help.
I read some articles and I think the problem is about context.
What Should I do?
In your view controller, replace the line:
#synthesize managedObjectContext;
With this:
- (NSManagedObjectContext *) managedObjectContext {
return ((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;
}
Instead of storing another, different object context in your view controller, this property will return the object context that you set up in the app delegate.
There are other ways to do this, such as creating a Core Data helper class following the Singleton pattern (as #NewYork167 suggests), but this should at least solve your current problem.
For any future reference, you can also try subclassing the NSManagedObjectContext like this:
#interface MyManagedObjectContext : NSManagedObjectContext
+ (MyManagedObjectContext *)mainThreadContext;
#end
#implementation MyManagedObjectContext
+ (MyManagedObjectContext *)mainThreadContext;
{
static MyManagedObjectContext *moc;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
moc = [[self alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// Setup persistent store coordinator here
});
return moc;
}
#end
Reference: Best practices for passing NSManagedObjectContext around to UITabBarController child view controllers?

No visible #interface for 'NSManagedObjectContext' declares

[self.managedObjectContext deletedObjects:lastPoint];
This line shows me an error
No visible #interface for 'NSManagedObjectContext' declares the selector 'deletedObjects'.
Here is my code
can any one solve this?
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.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* crete the fetch request first*/
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:#"Rectangle"];
NSError *requestError = nil;
/*And execute the fetch request on the context*/
NSArray *rectangle = [self.managedObjectContext executeFetchRequest:fetchRequest error:&requestError];
/*make sure we get the array*/
if ([rectangle count] > 0) {
/*delete the last person in the array*/
Rectangle *lastPoint = [rectangle lastObject];
[self.managedObjectContext deletedObjects:lastPoint];
if ([lastPoint isDeleted]) {
NSLog(#"Successfully deleted the last point...");
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]) {
NSLog(#"successfully saved the context");
} else {
NSLog(#"Failed to save the context");
}
} else {
NSLog(#"Failed to delete the last point");
}
} else {
NSLog(#"Could not find any rectangle entities in the context.");
}
return YES;
}
The error message
No visible #interface for 'NSManagedObjectContext' declares the
selector 'deletedObjects'.
tells you that the class NSManagedObjectContext doesn't implement the method deletedObjects. You can check this in the API documentation.
You can use deleteObject: to delete single objects. So change your code to:
[self.managedObjectContext deleteObject:lastPoint];
As the documentation says deletedObjects is the read only property, so it has only getter method without any parameters
So you should access it just by using next
self.managedObjectContext.deletedObjects

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
}
}
}

Core Data - failing to load data, entity not found

I have created a simple 1 entity data model through Core Data. I add an entity in "didFinishLaunchingWithOptions" of "AppDelegate". Then, I am trying to load the data of the model to an array and then a table view.
I am aware that there are similar post, but I still can't find out whats wrong with my code.
List of things I have tried and checked:
The entity is added properly into the model
I have already checked the entity names and they are correct.
I have tried deleting the app and clean rebuilding it but still nothing.
So there must be a more major issue with my code. Any help is appreciated.
Here is my error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'FavoritesInfo'
AppDelegate.h
#import <UIKit/UIKit.h>
#import "favTable.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) favTable *viewController;
#property (strong, nonatomic) UINavigationController *navController;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory; // reference files for core data
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
#synthesize navController = _navController;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *favoritesInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"FavoritesInfo"
inManagedObjectContext:context];
[favoritesInfo setValue:#"Product 1" forKey:#"name"];
[favoritesInfo setValue:[NSNumber numberWithInt:15] forKey:#"score"];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
return YES;
}
Then in the class of the table viewcontroller favtable.h
#import <UIKit/UIKit.h>
#interface favTable : UITableViewController <NSFetchedResultsControllerDelegate>
{
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSArray *favArr;
int num;
}
#property (nonatomic, strong) NSArray *favArr;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#end
favtable.m viewdidload
#import "favTable.h"
#import "AppDelegate.h"
#interface favTable ()
#end
#implementation favTable
#synthesize favArr;
#synthesize spVC;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize fetchedResultsController;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Favorites";
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"FavoritesInfo" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error=nil;
self.favArr=[managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (error!=nil) {
NSLog(#" fetchError=%#,details=%#",error,error.userInfo);
}
}
Your managedObjectContext is not set in your ViewController.
Set it in your AppDelegate didFinishLaunchingWithOptions, usually looks like:
ViewControllerClass *controller = (ViewControllerClass*)self.window.rootViewController;
or with a navigation controller:
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
ViewControllerClass *controller = (ViewControllerClass *)navigationController.topViewController;
And then:
controller.managedObjectContext = self.managedObjectContext;
In my favtable.m class I added this to set the managedObjectContext and it works properly.
self.managedObjectContext = ((AppDelegate *) [UIApplication sharedApplication].delegate).managedObjectContext;

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.

Resources