Extract attributes from NSManagedObject array - iphone

NSFetchRequest *req = [NSFetchRequest init];
NSEntityDescription *descr = [NSEntityDescription entityForName:#"City" inManagedObjectContext:context];
[req setEntity:descr];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"streetName" ascending:YES];
[req setSortDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
//fetch
NSError *error;
NSArray *result = [context executeFetchRequest:req error:&error];
//extract names
NSMutableArray *streets = [[NSMutableArray alloc] init];
for () {
??? = [array objectAtIndex:i];
[streets addObject:name];
}
I expected Core Data to be little more intuitive. I am new in it and I could use some help.
I fetched all objects(rows) from the entity (table) City. Now I have an array of objects. From the array I need to extract the attribute “streetName” to an array which will feed the picker. I figured I need to do it in the loop but I could not figure out the way to do it.
Please help.
I have a background with SQL but Core Data is still a big mystery to me. Is there any publication which would take a SQL statement and show comparable Core Data syntax?
Thanks.

It's very simple because of key-value coding:
NSArray *streets = [result valueForKey:#"streetName"];

i think core data changed quite a bit. here is how i do my fetch now
NSError *error;
NSFetchRequest *fr =[NSFetchRequest fetchRequestWithEntityName:#"Category"];
[fr setPredicate:[NSPredicate predicateWithFormat:#"name == \"myCategpry\""]];
NSArray *rs = [self.managedObjectContext executeFetchRequest:fr error:&error];
for (NSManagedObject *index in rs) {
NSLog(#"%#",[index primitiveValueForKey:#"name"]);
}

Related

How to sort a fetch in Core Data

I'm doing a fetch of data to show it in a UITableView, I do the fetch but I want to sort them by date of creation or by any sort method.
Here is the method:
-(NSArray *) lesStations {
NSManagedObjectContext *moc = [[AppDelegate sharedAppDelegate]managedObjectContext];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Station" inManagedObjectContext:moc];
[fetch setEntity:entity];
NSError *error;
NSArray *result = [moc executeFetchRequest:fetch error:&error];
if (!result) {
return nil;
}
return result;
}
This should work
-(NSArray *) lesStations {
NSManagedObjectContext *moc = [[AppDelegate sharedAppDelegate]managedObjectContext];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Station" inManagedObjectContext:moc];
[fetch setEntity:entity];
NSError *error;
NSArray *result = [moc executeFetchRequest:fetch error:&error];
if (!result) {
return nil;
}
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:"creationDate" ascending:YES];
NSArray *sortedResults = [result sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
return sortedResults;
}
You have 2 options: get the results sorted or sort the NSArray with the results:
NSFetchRequest could be set a NSArray of NSSortDescriptor
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"place" ascending:NO]; //the key is the attribute you want to sort by
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
You can also sort the returned NSArray (see all instance methods of NSArray starting with sortedArray...)
I suggest using the first approach when working with CoreData. The second one is just informative when working with arrays...
You can sort fetch results by setting sortDescriptors for fetch, e.g.
fetch.sortDescriptors = [NSArray arrayWithObjects:[[NSSortDescriptor alloc] initWithKey: ascending: selector:], nil];
NSError *error;
NSArray *result = [moc executeFetchRequest:fetch error:&error];

How to extract data from a NSArray fill with NSDictionary?

i try to make a kind of "sql distinct" request with core data,
so i set up my NSFetchrequest like this
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"my_table" inManagedObjectContext:managedObjectContext]];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"first_property",#"second_property",nil]];
// Execute the fetch
NSError *error;
table_dom = [[NSArray alloc] init];
table_dom = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
this looks ok for me but I think I retrieve an NSArray fill with NSDictionary, is that rigth ?
So my question is how can I extract data from table_dom for a tableview, I try many things but no ones work ?
It has to be:
cell.textLabel.text = //"first property" and
cell.detailTextLabel.text = //"second_property"
Or perhaps to make it simple, can I retrieve objects with setReturnsDistinctResults instead of NSDictionary ?
Thanks
Why not you can access in forms of objects so for this
remove
[fetchRequest setResultType:NSDictionaryResultType];
and
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"first_property",#"second_property",nil]];
then Now
table_dom = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
table_dom having objects of your entity so where you use this array
extract objects and access both property first_property and second_property
by simply using . operator.
You are correct that you will get a NSArray filled with NSDictionary. First I would like to point out you have a memory leak in your code. table_dom = [[NSArray alloc] init]; is not necessary since executeFetchRequest:error: will return an NSArray. So just remove that line.
After you have your array you can do something like this:
NSDictionary *dict = [table_dom objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"first_property"];
cell.detailTextLabel.text = [dict objectForKey:#"second_property"];

How to count in coredata (aggregation)?

I am learning core data and particularly working on aggregation.
Current what I want to do : count the number of records from the table which is in to-many relationship with inverse relationship on some criteria.
Currently I am doing this :
NSExpression *ex = [NSExpression expressionForFunction:#"count:"
arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:#"ddname"]]];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ddtype == 'Home'"];
NSExpressionDescription *ed = [[NSExpressionDescription alloc] init];
[ed setName:#"countDDEvents"];
[ed setExpression:ex];
[ed setExpressionResultType:NSInteger16AttributeType];
NSArray *properties = [NSArray arrayWithObject:ed];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setPredicate:pred];
[request setPropertiesToFetch:properties];
[request setResultType:NSDictionaryResultType];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"DDEvent" inManagedObjectContext:[self.currentAccount managedObjectContext]];
[request setEntity:entity];
NSArray *results = [[self.currentAccount managedObjectContext] executeFetchRequest:request error:nil];
NSDictionary *dict = [results objectAtIndex:0];
NSLog(#"Average birthdate for female heroes: %#", [dict objectForKey:#"countDDEvents"]);
Its from jeff lemarche.
EDIT : and I have found my solution as
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ddtype == 'Home'"];
[request setPredicate:pred];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"DDEvent" inManagedObjectContext:[self.currentAccount managedObjectContext]];
[request setEntity:entity];
NSError *error = nil;
NSUInteger count = [[self.currentAccount managedObjectContext] countForFetchRequest:request error:&error];
It is working nicely .But I want to do more request of such type at a time . So i think this can't be a preferred way of getting the count .
EDIT :
So I think the approach would be the appropriate one ????
So can anyone tell me more efficient an preferred way of doing this .
Thanks .
I had to count about 10 000 entities and it slowed down my interface responsiveness a lot while doing it with countForFetchRequest..
Here is a way of doing it wth NSExpression:
- (NSUInteger) unfilteredFCsCount {
// Just the fetchRequest
NSFetchRequest *fetchRequest = [self unfilteredFCsFetchRequest];
[fetchRequest setResultType: NSDictionaryResultType];
// You can use any attribute of the entity. its important, because you are not counting
// the properties, but actually the entities
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: #"sortIndex_"]; // Does not really matter
NSExpression *maxExpression = [NSExpression expressionForFunction: #"count:"
arguments: [NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName: #"fcCount"];
[expressionDescription setExpression: maxExpression];
[expressionDescription setExpressionResultType: NSInteger32AttributeType];
[fetchRequest setPropertiesToFetch: [NSArray arrayWithObject:expressionDescription]];
NSUInteger fcCount = 0;
NSError *error = nil;
NSArray *results = nil;
results = [self.managedObjectContext executeFetchRequest: fetchRequest error: &error];
KSLog(KSLogLevelDebug, #"unfilteredFCsCount results: %#", results);
if([results count] > 0) {
NSNumber *count = [[results objectAtIndex: 0] objectForKey: #"fcCount"];
fcCount = [count intValue];
}
return fcCount;
}
Jeff LaMarche is just using this as a simple example. In practice, this need is so common that Key-Value Coding has a built in macro to handle it and other common collection operations.
See: The Key-Value Programming Guide: Set and Array Operators
In this case you would use the #count operator in your predicate.
Of course, hand tuning your own expression gives you fine control over your predicates but the operators handle 80% of such task.

iphone core data save not working

Im trying to save a list of Device classes (a custom class) using Core Data and retrieve it. But After I save it, my query, which is VERY simple, doesnt return any records.
My call to save the records always returns YES and no errors:
BOOL resultOfSave = [managedObjectContext save:&err];
My predicate for searching by the property userLogin is like so:
- (NSArray *) devicesForUser:(NSString *)username
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Device" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"userLogin = %#", username];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"macAddress" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (fetchResults == nil) {
// Handle the error.
NSLog(#"ERROR: nil fetch result array");
}
[request release];
NSLog(#"devicesForUser [%#] count %d", username, [fetchResults count]);
return fetchResults;
}
but I always get zero results, if I get rid of the predecate, I get all the objects, and if I loop through them I can see that the userLogin property for at least one of the object IS set to the username that I pass in...
Has anyone ever had an issue like this???
Thanks for any help you can give
Mark
In your predicate, change:
#"userLogin = %#"
...to:
#"userLogin == %#"

NSArray from NSSet - Do I have to sort it myself?

I've got data in an NSSet, and I need to get it into an NSArray.
Do I need to sort it myself (again, this came from Core Data) or can I get it out in a sorted order?
You can specify a sort when you retrieve data with an NSFetchRequest by setting the sortDescriptors property to an array of NSSortDescriptors. But if you already have it in an NSSet and don't want to make another fetch request, you can use:
[[theSet allObjects] sortedArrayUsingDescriptors:sortDescriptors];
It'll create an interim NSArray when you call allObjects and then another sorted array afterwards, so it's not 100% efficient, but the overhead should be negligible for reasonably-sized data sets (and certainly less than the cost of sorting).
Edit
Actually, I was wrong - NSSet has the sortedArrayUsingDescriptors: method too. So you can just call [theSet sortedArrayUsingDescriptors:descriptors] and do it all in one go.
You've got to sort it yourself, but it's not very hard...
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Sprocket" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortVariable" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
self.sprocketArray = mutableFetchResults;
[sortDescriptors release];
[sortDescriptor release];
[mutableFetchResults release];
[request release];