fetchObjectsForEntityName: not recognised as valid method - iphone

This code is really confusing me. When I type in fetchObjectsForEntityName, it doesn't offer suggestions, and then afterwards gives me a warning of No visible #interface for 'NSManagedObjectContext' declares the selector 'fetchObjectsForEntityName:withPredicate:'.
Here's the code:
-(SyncObject *)objectWithSyncID:(NSString *)syncID inContext:(NSManagedObjectContext *)context {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"syncID == %#", syncID];
NSSet *set = [context fetchObjectsForEntityName:#"SyncObject" withPredicate:predicate];

Because the method doesn't exist. I guess you copied some code from a tutorial but you didn't copy all of it. There should be a category on NSManagedObjectContext which defines and implements the method.

Related

NSOperationQueue operations filteredArrayUsingPredicate error

I have class MyOperation : NSOperation with #property (nonatomic, retain) NSString *oID;
And sometimes I need to cancel operation with specific oID. I'm trying to do this:
NSArray *operations = operationQueue.operations;
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat: #"oID == %#", _specificID]];
NSArray *arrayOperations = [operations filteredArrayUsingPredicate: predicate];
and get error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "oID == 0f5db97b-f127-4425-ad79-451d1f204016"'
Is it possible to filter operation from NSOperationQueue?
Your problem is that you are formatting a string, then sending that to the Predicate constructor method. It's already a formatter, and knows how to format the data you give it.
Basically, you need the format to look like:
oID == "0f5db97b-f127-4425-ad79-451d1f204016"
but you are getting
oID == 0f5db97b-f127-4425-ad79-451d1f204016
If you use the formatter by itself, you should get past this issue...
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"oID == %#", _specificID];
NOTE: The predicate formatter knows it should handle strings specially, and automatically adds the extra quotation characters when you pass a string to be formatted by %#'
I'm going to guess that the operations.queue is a mutable array (logging its class returns this '__NSArrayM'). What you should try is:
NSArray *operations = [NSArray arrayWithArray:operationQueue.operations];
That said, some operation may have completed (and been removed from the mutable queue) by the time the predicate is applied to it.

Searching arrays of objects with NSPredicate

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[displayItems removeAllObjects]; //clear array to ensure no repeat info
if ([searchText length] == 0) {
displayItems = (NSMutableArray *)allItems;
}
else {
//search by item category
NSPredicate *catPredicate = [NSPredicate predicateWithFormat:#"category
CONTAINS[cd] %#",searchText];
[searchable filterUsingPredicate:catPredicate];
//further search by item name
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd]
%#",searchText];
[searchable filterUsingPredicate:namePredicate];
displayItems = searchable;
searchable = (NSMutableArray *)allItems;
}
[self.searchResults reloadData];
}
This method is part of a simple searchable table view I am trying to create for a larger project. My code compiles and runs, and when i type something into the search bar the search function appears to work, but then the program crashes as soon as a second letter is typed. If I type two letters in a row, it throws 'NSInvalidArgumentException', reason: '-[_NSArrayI filterUsingPredicate:]: unrecognized selector sent to instance 0x6d6c040', but if I type one letter and then hit enter or backspace, it throws this guy 'NSInvalidArgumentException', reason: '-[_NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x6a7f300' when I type a second letter.
I am pretty new to objective-c, and this has me perplexed. Any help I could get would be greatly appreciated.... :-/ Still having issues since update.
"One does not simply cast NSArray into NSMutableArray and then call NSMutableArray methods on it" - Boromir
Create a mutable copy instead, like this:
searchable = [allItems mutableCopy];
NOTE: Make sure to release searchable when you are finished with it.
You have to use NSMutableArray to call the methods.
NSArray has a method "filteredArrayusingPredicate".
The simple solution is use NSMutableArray.

CoreData Basics Help

EDIT:
I have altered the NSPredicate as recommended so that my fetch code look like so. Having printed to the UITextView like this, when I press load it spits out the following:
<NSManagedObject: 0x1c7cf0>(entity: DatedText; id: 0x1420c0 <x - coredata://B52D4F88-0210-4AE2-9DA6-C05ED64FE389/DatedText/p12> ; data: <fault>)
So either its not getting any data data because it hasn't been saved/loaded correctly or I am trying to get the loaded result into a UITextView the incorrect way. Any ideas?
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *testEntity = [NSEntityDescription entityForName:#"DatedText" inManagedObjectContext:self.managedObjectContext];
[fetch setEntity:testEntity];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"dateSaved == %#", datePicker.date];
[fetch setPredicate:pred];
NSError *fetchError = nil;
NSArray *fetchedObjs = [self.managedObjectContext executeFetchRequest:fetch error:&fetchError];
if (fetchError != nil) {
NSLog(#" fetchError=%#,details=%#",fetchError,fetchError.userInfo);
return nil;
}
NSString *object = [NSString stringWithFormat:#"%#",[fetchedObjs objectAtIndex:0]];
noteTextView.text = object;
I have been having all sorts of problems working out how to use Core Data, so I have gone back to basics, new window based ipad project using core data.
I have added a view and some code which doesn't work, hehe. Im basically trying to save some text to a date, then when going back to that date, the text which was previously saved will be shown again.
There's a tutorial on iPhone developer site here. And there are several sample codes with Core Data as well. These should get you started.
I checked your project and aside from having to synthesize the CoreData properties, I also just noticed you were trying to assign an NSArray to your fetch predicate, but it actually expects an NSPredicate object. You should use this instead:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#)", datePicker.date];
[fetch setPredicate:pred];
If you want to set more than 1 predicate you should do that on your predicate string i.e.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#) AND (dateSaved <= %#", datePicker.date, [NSDate date]];
Cheers,
Rog
You most likely crashing because your ivar is managedObjectContext_ but you are using self.managedObjectContext. You also need to synthesize the core data ivars even if you provide a custom getter.
You're setting your NSFetchRequest's predicate to an NSArray, not an NSPredicate.
If you had posted the actual crash, it would probably say something like an unknown selector was sent to an instance of NSArray.

Querying Core Data with Predicates - iPhone

So I'm trying to fetch objects from core data. I have list of say 80 objects, and I want to be able to search through them using a UISearchBar. They are displayed in a table.
Using the apple documentation on predicates, I've put the following code in one
of the UISearchBar delegate methods.
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if (self.searchBar.text !=nil)
{
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"name LIKE %#", self.searchBar.text];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
else
{
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"All"];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort(); // Fail
}
[self.tableView reloadData];
[searchBar resignFirstResponder];
[_shadeView setAlpha:0.0f];
}
If I type in the search field an exact match to the name property of one of those objects, the search works, and it repopulates the table with a single cell with the name of the object. If I don't search the name exact, I end up with no results.
Any Thoughts?
It seems as though iPhone doesn't like the LIKE operator. I replaced it with 'contains[cd]' and it works the way I want it to.
use contains[cd] instead of like, and change:
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"All"];
to:
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"1=1"];
Did you try it using MATCH and regular expressions? Just curious to see if LIKE is something that should be avoided on the iPhone or not...
In typical Core Data application one should delete NSF fetchedResultsController:
[NSFetchedResultsController deleteCacheWithName: [self.fetchedResultsController cacheName]];
Or else you'll get an exception (ideally) or you'll have strange behavior.

Setting an attribute on an entity and retrieving it with "one-to-many" relations

I have been through the Apple Developer guides and tutorials and I been through 2 iPhone books brushing on the subject of Core Data.
I am used to handling the "value object"/"entity" side of things and then send them of to a web service or the likes. But on the iPhone I get to handle everything myself… cruel world :)
The Locations, TaggedLocations and PhotoLocations examples from the Apple Developer site do not give me the answers in a way I can "compute". I hope someone here can enlighten me.
I have set up my model using the datamodel GUI. two entities, Person and Dream.
Person has a personName string attribute and a one-to-many dreams relationship.
Dreams has a description string attribute and a one-to-one person relationship.
I have been setting up a simple tableView app.
First view is a list of persons and the second view is a list of their dreams.
This is how I add a person to the modelObjectContext:
Person *newPerson = (Person *)[NSEntityDescription
insertNewObjectForEntityForName:#"Person"
inManagedObjectContext:managedObjectContext];
[newPerson setPersonName:#"Ben Hur"];
OK, I then add a new dream to the context:
Dream *newDream = (Dream *)[NSEntityDescription
insertNewObjectForEntityForName:#"Dream"
inManagedObjectContext:managedObjectContext];
[newDream setDescription:#"I had a nightmare"];
I now add the dream to the person like this:
[newPerson addDreamObject:newDream];
Here it gets a bit hazy to me, because xcode generated different methods/accessors for me on the Person Class:
#class Dream;
#interface Person : NSManagedObject
{
}
#property (nonatomic, retain) NSString * personName;
#property (nonatomic, retain) NSSet* dream;
#end
#interface Person (CoreDataGeneratedAccessors)
- (void)addDreamObject:(Dream *)value;
- (void)removeDreamObject:(Dream *)value;
- (void)addDream:(NSSet *)value;
- (void)removeDream:(NSSet *)value;
#end
In other situations, where I did not have to handle the actual saving, retrieving, data. I would have build an entity/value object called person and given it an Array to store the dreams. But this is not a possible attribute type in core data, and not the way to do it, I have read (in here in similar threads too).
So how does this boilerplate code work?
Am I supposed to use the addDream and send it an NSSet filled with dreams? or can I just trust core data to instantiate this and exclusively use the addDreamObject send the Person entity objects of type Dreams?
I also save the context using the boilerplate code from xcode.
Now I wish to update the view with this person, more precisely his name.
In the cellForRowAtIndexPath method I give it this:
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:#"personName"] description];
Again all is well and the name is displayed on the list.
I set up my DreamViewController to take a Person object as a parameter.
Person *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
dreamView.selectedPerson = selectedObject;
Then I push the viewController onto the stack and we enter the DreamView. Here I can not seem to get at the at the dreams related to the person I "sent along" with the view.
This is what I'm trying in the DreamViewController's viewDidLoad method (selectedPerson is the accessor I use to pass the Person object):
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"One Person";
NSManagedObjectContext *context = selectedPerson.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Dream"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// Handle the error.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
NSMutableArray *mutableArray = [fetchedObjects mutableCopy];
self.dreamArray = mutableArray;
NSLog(#"the length of dreamArray: %i",[self.dreamArray count] );
Dream *d = [dreamArray objectAtIndex:0];
NSLog(#"The Dream object says: %#", [d description]);
[mutableArray release];
[fetchRequest release];
}
I really can't seem to get the hang of this and my current experience with Objective C does not allow me to just grab the "best practice" essence from between the lines of Apple's documentation.
You need to correct a mistake you made in your model, to begin with. You can NOT have an attribute called "description" in your dreams entity: this is forbidden because "description" it's the name of a method.
From the Apple documentation (Core Data programming guide):
Note that a property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject, for example, you cannot give a property the name “description” (see NSPropertyDescription).
The difference between addDreamObject: and addDream: is that the former is used to insert a Dream object in the to-many relationship, while the latter is used to insert or replace one-shot the contexts of the to-many relationship.
You should not use
cell.textLabel.text = [[managedObject valueForKey:#"personName"] description];
you should use simply
cell.textLabel.text = [managedObject valueForKey:#"personName"];
Regarding the dreams related to your person, you do not need an additional fetch request. Once you have your person object, you simply access that person's dreams as follows:
for(Dream *dream in person.dreams){
// process your Dream object
}
Finally, it is not clear why you do not pass explicitly the managed object context to your DreamViewController as an instance variable. This is common practice, also shown in Apple sample codes. Another error is checking for
if (fetchedObjects == nil)
because it is legal to return nil if the query actually found no objects; you must instead check if your NSError object is not nil (you must initialize it to nil BEFORE executing your fetch request):
if(error)
The statement
NSLog(#"The Dream object says: %#", [d description]);
may even crash your application, as explained at the beginning of my answer.