NSFetchResultController i am using predicate with attribute in array? - iphone

In NSFetchRsultController I am using:
[NSPredicate predicateWithFormat:#"type in %#", myArray];
I want the data in the order of the data in the array, but NSSortDescriptor is mandatory for the NSFetchResultController, so what NSSortDescriptor I have to use?

You can use sortDescriptors to order the data in order of your array.
The sort descriptors specify how the objects returned when the fetch request is issued should be ordered—for example by last name then by first name. The sort descriptors are applied in the order in which they appear in the sortDescriptors array (serially in lowest-array-index-first order).
Code example:
...
NSMutableArray * sortDescriptors = [[NSMutableArray alloc] initWithCapacity:[myArray count]];
for (NSString * key in myArray)
[sortDescriptors addObject:[[NSSortDescriptor alloc] initWithKey:key ascending:NO]];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
...

user1800529,
It appears you want the order sequential order things were inserted into your database. Core Data makes no guarantees about that order. Hence, you need to pick something to sort on. I use creation time, which is in most of my entities, but you could easily use another attribute.
Andrew

Related

How to sort NSArray of objects based on one attribute

I am trying to sort an array of managed objects alphabetically. The attribue that they need to be sorted by is the name of the object (NSString) with is one of the managed attributes. Currently I am putting all of the names in an array of strings and then using sortedNameArray = [sortedNameArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]; and then enumerating them back into an array with the objects. This falls apart when two names are the same so I really need to be able to sort by one attribute. How should I go about doing this?
Use NSSortDescriptor. Just search the documentation on it and there some very simple examples you can copy right over. Here is a simplified example:
NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:#"MyStringVariableName" ascending:YES];
NSArray *descriptors = [NSArray arrayWithObject:valueDescriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:descriptors];
And just like that you have a sorted array.
You can do this by using NSSortDescriptor,
eg.
`NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc]initWithKey:#"distance" ascending:YES];`
// Here I am sorting on behalf of distance. You should write your own key.
NSArray * descriptors = [NSArray arrayWithObject:valueDescriptor];
NSArray *sortedArray=[yourArray sortedArrayUsingDescriptors:descriptors];`

iphone coredata fetch-request sorting

I'm using core data and fetching the results successfully. I've few questions regarding core data
1. When I add a record, will it be added at the end or at the start of entity.
2. I'm using following code to fetch the data. Array is being populated with all the records. But they are not in the same order as I entered records into entity. why? on what basis default sorting is used?
NSFetchRequest* allLatest = [[NSFetchRequest alloc] init];
[allLatest setEntity:[NSEntityDescription entityForName:#"Latest" inManagedObjectContext:[self managedObjectContext]]];
NSError* error = nil;
NSArray* records = [managedObjectContext executeFetchRequest:allLatest error:&error];
[allLatest release];
3. The way that I enter the records, 1,2,3,4......... after some time, I want to delete the records that I entered first(i mean oldest data). Something like delete oldest two records. How to do it?
A sort on the array you have looks like this:
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"SortKey" ascending:YES] autorelease];
NSArray *sortedList = [records sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];
The initWithKey: argument is the property you would like to sort on. If you have multiple keys to sort on, they can be added to the sortedArrayUsingDescriptors: argument as a list. The list will be sorted by the first descriptor, then each group by the next descriptors.
-dan
Ordering is not guaranteed in any way. If you care about order, you need to include an attribute in your entity (for example, call it "sequenceNumber") and use that in a sort descriptor with your NSFetchRequest.

Core data, sorting one-to-many child objects

So, lets say I have a store of parents children and the parent has a one to many relationship to children (parent.children) and they all have first names. Now, on the initial fetch for parents I can specify a sort descriptor to get them back in order of first name but how can I request the children in order? If I do a [parent.children allObjects] it just gives them back in a jumble and I'd have to sort after the fact, every time.
Thanks,
Sam
If you just want to use an NSArray, and not an NSFetchedResultsController, there's another way:
NSSortDescriptor *alphaSort = [NSSortDescriptor sortDescriptorWithKey:#"firstName" ascending:YES];
NSArray *children = [[parent.children allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:alphaSort]];
Sam,
If I read your question correctly, you want to set up a fetch that returns a sorted list of the children of a specific parent. To do this, I would set up a fetch for "children" entities and then use a predicate to limit the results:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"children" inManagedObjectContext:moc]];
[request setSortDescriptors:[NSArray initWithObject:[[NSSortDescriptor alloc] initWithKey:#"firstName" ascending:YES]];
[request setPredicate:[NSPredicate predicateWithFormat:#"(parent == %#)", parent]];
Obviously, your entity and attribute names may be different. In the last line, the parent variable should be a reference to the NSManagedObject instance of the parent whose children you want.

iPhone Core Data - Simple Query

I am trying to create a Core Data iPhone application. One of the entities I'm tracking is cars, and one attribute of each car is "manufacturer".
In the "edit car" section of my application, I have a UIPickerView that needs to be loaded with each of the unique manufacturers that have previously been entered into the system. What I'm trying to do is create an NSFetchRequest to get an array of unique "manufacturer" attributes and use that to populate the UIPickerView.
The problem I'm running into is that whether there are zero records or 100 in the data store, there is always one record in the executed fetch request at element zero with a value #"".
Am I doing this wrong or is there an easier way to do this? I wish I could just run a quick sql query!!!
My code is below:
// Populate the manufacturerNameList array
NSManagedObjectContext *moc = [self.selectedLease managedObjectContext];
NSEntityDescription *ed = [NSEntityDescription entityForName:#"Car" inManagedObjectContext:moc];
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:ed];
// Get only manufacturer and only uniques
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"manufacturer",nil]];
[fetchRequest setReturnsDistinctResults:YES];
// Sort by manufacturer in ascending order
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"manufacturer" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error = nil;
self.manufacturerNameList = [moc executeFetchRequest:fetchRequest error:&error];
if (error) {
// Handle the error
}
NSLog(#"The count of self.propertyNameList is %i",[self.propertyNameList count]);
Thanks!
manufacturerNameList is going to be an array of Car entities, not manufacturer names. Also, you need to pass an NSArray of NSPropertyDescription objects to setPropertiesToFetch not just attribute names.
Here is how you set the property:
NSDictionary *entityProperties = [ed propertiesByName];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:[entityProperties objectForKey:#"manufacturer"], nil]];
The results from executeFetchRequest: will be an NSArray of Car entities, so you'll then have to extract the manufacturer attribute values in a loop or something.
You may want to consider creating a Manufacturer entity that your Car entity references, that will allow you to query more in the way you are attempting to right now.
Another approach would be to create an entity for manufacturers and have a relationship between Car and Manufacturer such that a Car has one Manufacturer and a Manufacturer has many Cars:
Car <<--> Manufacturer
The Manufacturer entity could have a string attribute its "name".
Then, you could get the full list of manufacturer names by fetching all the Manufacturer objects and looking at the "name" property.
The simplest explanation is that you have a car entity that has an empty manufacturer value. When the predicate sorts the fetch, the blank string will be ranked first.
I would log the entire self.propertyNameList and see what you're actually getting back.

disordered/ordered context fetching

I cannot understanding why values assign to array objects become "disordered" after executing executeFetchRequest. Well, I'm not certain that fetching is the problem here. Here's the code.
objects=[NSArray arrayWithObjects:#"a",#"b",#"c",#"d",#"e",nil];
NSManagedObject *DB = nil;
for (int i=0;i<[objects count];i++){
DB = [NSEntityDescription
insertNewObjectForEntityForName:#"dbTable"
inManagedObjectContext:context];
[DB setValue:[objects objectAtIndex:i] forKey:#"item"];
[DB setValue:[NSString stringWithFormat:#"%3.2f", 0] forKey:#"value"];
}
objects = [context executeFetchRequest:request error:&error];
Printings
new wrong ordering after fetch execution into array objects
index 0 :: Item: d
index 1 :: Item: c
index 2 :: Item: e
index 3 :: Item: b
index 4 :: Item: a
thank you.
Due to the underlying database architecture, Core Data stores all objects and to-many references in an unordered fashion. The order you get back from a fetch request is not guaranteed, unless you apply an NSSortDescriptor, as Alex describes. This thread in the Cocoa mailing list details the issues involved, as well as some potential solutions.
These solutions include having an index property that you sort on when performing a fetch request, or implementing a linked list of managed objects and traversing that in order. Brian Webster has created a subclass of NSManagedObject that lets you maintain ordered to-many relationships in your Core Data objects, for which the source code can be found here.
Apply an NSSortDescriptor to your fetch request, e.g.:
NSSortDescriptor *itemDescriptor = [[NSSortDescriptor alloc] initWithKey:#"item" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:itemDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[itemDescriptor release];
will sort on the item name. You could use value, instead.
When you execute a fetch request without specifying that you want your items sorted by a specific key, you get a result array which is not ordered. You can extend your fetch request with a sort descriptor using a code snippet such as the following one.
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"value" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];