How to use the method readDataForTable? - ios

I'm developing an App which uses a DataBase managed from MagicalRecord. App displays names which user can add tapping + button. + button opens an UIAlert where user can type a new name and tapping OK name is added to a DataBase.
Trouble is that, everytime user add a new name, table has to be reloaded to display new name.
To reload table I imported CoreDataHelper and I'm using this method: (I've found everything there: https://github.com/kgudger/AssignLine )
#property (strong, nonatomic) NSMutableArray * eventiArray; // Array which populate table
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
-(void)readDataForTable {
_eventiArray = [CoreDataHelper getObjectsForEntity:#"Entity" withSortKey:#"nomeEvento" andSortAscending:YES andContext: _managedObjectContext];
[self.tableView reloadData]; }
// (Entity is the name of NSManagedObject SubClass)
// (nomeEvento is the name of NSString in NSManagedObject SubClass)
Running, it crashes saying *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Entity'' but I can't understand the reason, can somebody help me? Thank you!!!

My recommendation would be to use MagicalRecord to load the data.
-(void)readDataForTable {
self.eventiArray = [YourEntity MR_findAllSortedBy:#"nomeEvento" ascending:YES inContext:[NSManagedObjectContext MR_defaultContext]];
[self.tableView reloadData];
}
If you want to use it in context
[YourEntity MR_findAllSortedBy:#"nomeEvento" ascending:YES inContext:self.managedObjectContext];
or
[YourEntity MR_findAllSortedBy:#"nomeEvento" ascending:YES];

Related

Accessing an instance throws exception - NSDictionary NSArray

I am a beginner in Objective-C and do struggle a bit with dictionaries and arrays.
My goal is to create a table view where every cell contains a picture from a server. The url for the pic comes from a JSON call. I downloaded the example from Apple called "lazy table view" and tried to merge it with the one I found inside a Standford iOS Class. So far everything works, besides the picture. Xcode throws the following exception, once I try to access the icon:
-[__NSCFDictionary Icon]: unrecognized selector sent to instance 0x10b845ff0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary Icon]: unrecognized selector sent to instance 0x10b845ff0'
The code in question looks like this:
#interface FlickrPhotosTVC : UITableViewController
#property (nonatomic, strong) NSArray *photos;
#end
#interface ClRecord : NSObject
#property (nonatomic, strong) UIImage *Icon;
#define FLICKR_PHOTO_TITLE #"title"
ClRecord *clRecord = self.photos[indexPath.row];
cell.textLabel.text = [clRecord valueForKeyPath:FLICKR_PHOTO_TITLE]; // works
if (clRecord.Icon) NSLog(#"test"); // throws exeption
Somehow this seems to be releated with the types. Trying to access an array, while accesing a dictionory or similar. I found some releated posts on stack, but could not solve it so far.
Thank you for any help!
The objects stored in self.photos seems to be dictionaries objects and not ClRecord objects. The error you get say that you are calling Icon method on a dictionary object.
Check where you fill your photos array to make sure you put ClRecord objects in it and not dictionaries objects.
You could do NSLog(#"My photos array is ---%#",self.photos);
This will give you what exactly you have in your array.
Case 1: If you have a dictionary objects then :- You should do NSDictionary *dict = self.photos[indexPath.row]; ClRecord *clRecord = [dict objectForKey:#"YourKeyForImage"];
Case2: If you have images as you expect, then make sure you import ClRecord header file, you have non nil object at your specified [indexPath.row] index and other necessary initializations.
Hope this helps. Link1

how do I configure the view for NSNumber when trying to set the value from Core Data

I am building my project using a master detail VC template with core data.
I am trying to set the values for my attributes in the detail window.
When transitioning from the MasterViewController to the FoodDetailViewController, my NSString attribute works perfectly.
When I add code to add the calorie value attribute (set up as integer 16) my app crashes.
I generated a class file for my entity and the calories property is declared like this:
#property (nonatomic, retain) NSNumber * calories;
This is how I set up the transition.
In MasterViewController.m in prepareForSegue, I set the keyString as such:
foodDetailVC.calorieKeyString = #"calories”;
Then in FoodDetailViewController.h I did:
#property (nonatomic, strong) NSString *calorieKeyString;
in FoodDetailViewController.m I did:
-(void)configureView
{
if (self.managedNutritionValuesObject) {
//refresh content to ensure most up to date data
[self.managedObjectContext refreshObject:self.managedNutritionValuesObject
mergeChanges:YES];
//covert NSNumber values to NSString values
NSString *caloriesString = [NSString stringWithFormat:#"%#",
self.managedNutritionValuesObject.calories];
//set nutrition values in text fields
//these first two lines are for food text field
self.foodNameTextField.text = [self.managedNutritionValuesObject
valueForKey:self.foodNameKeyString];
self.foodNameTextField.clearsOnBeginEditing = YES;
self.caloriesTextField.text = [caloriesString valueForKey:self.calorieKeyString];
self.caloriesTextField.text = caloriesString;
}
}
the crash log says it is crashing on configure view and I get this message:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason:
'[<__NSCFString 0x8b44e20> valueForUndefinedKey:]: this class is not key value coding-compliant for the key calories.’
Any help would be greatly appreciated,
Thanks
self.caloriesTextField.text = [self.managedNutritionValuesObject valueForKey:#"calories"];

selector and PerformSelector

I have a UITableView with several sections. Each section contains a different set of data: phoneNumbers, addresses....
For each of those sets I have a model: PhoneNumber, Address. They're completely different but have some methods in common.
In my UITableView I have an array containing those models/classnames:
NSMutableArray *classNames;
In the viewDidLoad of my UITableView I do some initializations for all those sections:
//section 1: PhoneNumbers
phoneNumbers = [PhoneNumbers getAllIDs];
if (phoneNumbers && (phoneNumbers.count >0)) {
[classNames addObject:#"PhoneNumber"];
[dataIDs addObject:phoneNumbers];
}
I do this again for all the other sections/models:
//section 2: Addresses
addresses = [Address getAllIDs];
if (addresses && (addresses.count >0)) {
[classNames addObject:#"Address"];
[dataIDs addObject:addresses];
}
// section 3: .....
Ok so far for initialization. This looks good and works fine.
Then later on in my cellForRowAtIndexPath I'm retrieving the actual data via those ID's
NSInteger section = [indexPath section];
NSInteger row = [indexPath row];
NSArray *rows = [dataIDs objectAtIndex:section];
NSNumber *recordID = [rows objectAtIndex:row];
I then figure out in what class we have to fetch the actual data:
Class displayedDataClass = NSClassFromString ([classNames objectAtIndex:section]);
and get the data to populate the cell.
id displayedRecord = [[displayedDataClass alloc] init];
[displayedRecord getByID:recordID];
I can then set the labels in my cell using :
[cell.someLabel setText:[displayRecord fullDesciption]];
So far so good, I succesfully abstracted everything, the cellForRowAtIndexPathdoesn't need to know where things come from, as long as those classes respond to the methods for retrieving the data for the labels (in the case above fullDesciption)
Now I need an actionButton in every Cell performing some kind of action
To make sure I understood the concept of selectors and performSelection I just quick and dirty made in action in my TableView Class:
- (void) buttonTarget {
NSLog (#"yes");
}
And in my cellForRowAtIndexPath method created a button with the following target:
button addTarget:self action:#selector(buttonTarget) forControlEvents:UIControlEventTouchUpInside];
Ok, so far so good, things work like expected. But this is not what I really wanted. The action should not be performed here, but in the actual class (PhoneNumber,Address,...).
To keep things clean I made a model Action, containing the icon for the button, a description and the selector:
#interface Action : NSObject
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) UIImage *icon;
#property (nonatomic ) SEL selector;
#end
In my PhoneNumber class (and similar classes) the action is set to the correct selector:
Action *phoneAction = [[Action alloc] init];
phoneAction.description = NSLocalizedString(#"Call", #"Call button description");
phoneAction.icon = [UIImage imageNamed:#"phone"];
phoneAction.selector = #selector(callPhone);
Of course callPhone is implemented in the PhoneNumber class.
In my TableView I then get the actions for that cell
action = [displayedRecord action];
I then try to use that selector in my Button:
[button addTarget:displayedRecord action:[action selector] forControlEvents:UIControlEventTouchUpInside];
But here things go wrong: we never arrive in that method and I get the following error:
[UIDeviceWhiteColor callPhone]: unrecognized selector sent to instance
0x874af90 2013-12-29 23:23:03.629 thinx[27242:907] * Terminating app
due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIDeviceWhiteColor callPhone]: unrecognized selector sent to
instance 0x874af90'
Sounds like you have a zombie. When you get an action being sent to an object that makes no sense, it usually means that your object is being deallocated before you can send a message to it.
In your case, you're adding "displayedRecord" as the target for your button.
In order for that to work, you need to keep a strong reference to displayedRecord call for the lifetime of your button object. What owns your displayedRecord object?
If you can't debug this from looking at your code you can use the zombies instrument to try to figure it out.
In your unrecognized selector error you sent the message to an object called UIDeviceWhiteColor. Does that class have a method called callPhone? It seems to me that displayedRecord is not pointing to the object you think it is.

CoreData error how to write core data back

I am just trying to wrap my head around core data. I have managed to load some data into it i applicationDidFinishLaunching but now I want to do something a little more complicated. When I unwind from view controller B back to viewController A, I want to send the recipeName from B back to A and then write it to core data. I get this error:
CoreData: error: Failed to call designated initializer on NSManagedObject class 'Recipe'
2013-11-01 19:10:07.886 RecipesWithCore[96409:70b] -[Recipe setRecipeName:]: unrecognized selector sent to instance 0x8c8cf40
2013-11-01 19:10:07.890 RecipesWithCore[96409:70b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Recipe setRecipeName:]: unrecognized selector sent to instance 0x8c8cf40'
This is my unwindToRecipes:
-(IBAction) unwindToRecipes:(UIStoryboardSegue *)segue{
DBKAddRecipeViewController *source = [segue sourceViewController];
NSString *rn = source.recipe.recipeName;
if (recipe != nil){
//Add the recipe to coredata
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newRecipe = [NSEntityDescription
insertNewObjectForEntityForName:#"Recipe"
inManagedObjectContext:context];
[newRecipe setValue:rn forKey:#"recipeName"];
}
}
It seems that insertNewObject returns a Recipe class, not a NSManagedObject. Check your Recipe class and make sure you have the correct declarations in its #interface, as well as #dynamic recipeName in its #implementation. Also check your managed object model and make sure the attribute name is indeed recipeName.

Core Data with multiple viewControllers

I'm having a lot of difficulty getting core data to work in my application. I'm perfectly comfortable with core data in a table view controller and even with core data in a single view application. I'm unable however to get my program to function properly in with multiple view controllers.
I've read through Zarra's core data book and bought pro core data for iOS and have gone through the projects listed but every one of them is used in a TableView controller. with the exception of the shapes application in pro core data for iOS.
Does anyone know of any examples (code or tutorials) that would demonstrate how to do a program with multiple view controllers and core data?
What I would like to do is have buttons on the first (instead of tableview cells) that will segue to the the next viewController. On the second view controller I would like that information populated with information from the set of the first entity,
so I have something like this so far where the first entity is:
House
houseName (attribute)
occupants (relationship)
Person
personName (attribute)
household (relationship)
occupants <-->>household (one to many )
{
...
int i = //house selected on previous view controller;
NSManagedObject *people = [[self sortOccupants] objectAtIndex:i];
textField01.text = [NSString stringWithFormat:#"%#",[[people valueForKey:#"personName"]description]];
}
the sort occupants looks like this:
-(NSArray *)sortOccupants
{
NSSortDescriptor *sortPeopleInHouse = [[NSSortDescriptor alloc] initWithKey:#"personName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortPeopleInHouse, nil];
return [[(NSSet *)[house valueForKey:#"occupants"] allObjects] sortedArrayUsingDescriptors:sortDescriptors];
}
Any Ideas would be great but if you can point me to sample code that would show this I would be most appreciative.
Thanks,
The way I would approach this is to generate NSManagedObject subclasses for your entities (makes it much more readable and type-safe).
Then, I would create a new init method in the second view controller. initWithHouse:(House *)house or something:
#property (nonatomic, strong) House * currentHouse;
#property (nonatomic, strong) NSArray * sortedOccupants; // Array of People objects
-(id) initWithHouse:(House *)house
{
if (self = [super init])
{
// Managed Object Context available from [currentHouse managedObjectContext]
currentHouse = house;
sortedOccupants = [self sortOccupants:house.occupants];
}
return self;
}
-(NSArray *)sortOccupants: (NSSet *)occupants
{
NSSortDescriptor *sortPeopleInHouse = [[NSSortDescriptor alloc] initWithKey:#"personName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortPeopleInHouse, nil];
return [occupants allObjects] sortedArrayUsingDescriptors:sortDescriptors];
}
Hope that helps.
Maybe the key is that each view controller should have
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
in its header.
Before you push a view controller you give it a managed object context. In this new view controller you can have your typical methods for searching and saving the context.
You start with a home view controller, which is really a list of people. You select a person and launch a person view controller. You should pass a managed object context and an instance of Person to this person view controller.

Resources