Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

(sorry about the long title)

I have a custom object Person, which in turn has an NSSet which has several custom objects called Appointment. A Person therefore can have several appointments. Appointment has the values startTime and endTime.

These are Core Data NSMangagedObject classes.

@interface Person : NSManagedObject

@property (nonatomic, retain) NSString *personName;
@property (nonatomic, retain) NSSet *appointments;

// etc

@end


@interface Appointment : NSManagedObject

@property (nonatomic, retain) NSNumber * startSecond;
@property (nonatomic, retain) NSNumber * endSecond;

// etc

@end

How would I get a list of Persons, in order of the earliest startSecond within any of their appointments?

share|improve this question
 
In a single fetch? –  MadhavanRP Jan 30 '12 at 10:18
1  
1  
You should probably make a custom compare function that first fetches the earliest of dates of the appointments of a person. (If you add each appointment one by one every time you could probably keep a variable that holds the earliest time anyway, just check the new appointment with the latest lowest of times there). Then you can simply compare: each person and their earliest date with each other with a simple date comparison. This should be doable for NSManagedObjects as well since they inherit from NSObject. I could probably write you an example but first let me know if this is what you seek –  Totumus Maximus Feb 1 '12 at 12:21
 
Is there a way to do it without adding the extra variable? –  cannyboy Feb 1 '12 at 15:46
add comment

3 Answers

up vote 24 down vote accepted
+250

You can use sort descriptors and KVC collection operators:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"[email protected]" ascending:YES];

For example, in a CoreData fetch:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Person" inManagedObjectContext:context]];

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"[email protected]" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

NSArray *sortedResults = [context executeFetchRequest:request error:nil];
[request release];

Or just sorting an array:

NSArray *people = ...;
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"[email protected]" ascending:YES];

NSArray *sortedPeople = [people sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

More information on KVC collection operators can be found in the KVC Programming Guide.

share|improve this answer
 
if you are using Core Data this is the way to go... +1 –  Artanis Feb 1 '12 at 23:18
1  
Just a little explanation: NSSortDescriptors access the value by which they are sorting using Key-Value-Coding. So you can use the key "[email protected]" which basically means: in the collection appointments, get the startSecond of the object, whose startSecond is the smallest among the objects in the collection. then it just sorts by the returned value –  Ahti Feb 2 '12 at 1:09
add comment

A suggestion:

// Sorting key
NSString *key = @"startSecond";

// A mutable array version of your list of Persons.
NSMutableArray *a = [NSMutableArray arrayWithObjects:Person1, Person2, Person3, nil];

// Then use the sorted appointements to get your sorted person array.
[a sortUsingComparator:^NSComparisonResult(Person *p1, Person *p2) {
    NSSortDescriptor *sortDesc1 = [NSSortDescriptor sortDescriptorWithKey:key ascending:NO];
    NSArray *sortedApp1 = [p1.appointements sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDesc1]];

    NSSortDescriptor *sortDesc2 = [NSSortDescriptor sortDescriptorWithKey:key ascending:NO];
    NSArray *sortedApp2 = [p2.appointements sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDesc2]];

    return [[[sortedApp1 objectAtIndex:0] valueForKey:key] compare:[[sortedApp2 objectAtIndex:0] valueForKey:key]];
}
share|improve this answer
 
I'm getting an 'index 0 beyond bounds for empty array' error for this part of the return statement: [sortedApp1 objectAtIndex:0] –  cannyboy Feb 1 '12 at 15:44
 
This would be very slow, since it would require pulling into memory all appointment objects. –  Daniel Eggert Feb 3 '12 at 8:21
add comment

If you have the data in an NSArray form you can sort it like this:

NSArray *sortedPersonArray = [coreDataPersonArray sortedArrayUsingSelector:@selector(compare:)];

- (NSComparisonResult)compare:(Person *)personObject {
    return [self.startSecond compare:personObject.startSecond];
}
share|improve this answer
 
This works for me perfectly as I am not using CoreData. Thanks Artanis –  iOSAppDev May 28 at 6:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.