Reputation: 2522
I'm developing a Core Data Application. I have a main table that displays Orders with different Statuses: New, Accepted, Delivered, etc.
The problem I'm having is that I need to order each section by differently Criteria. For example:
So this is the code that I have now when fetching results:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CDOrder"];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"orderPosition" ascending:YES],[NSSortDescriptor sortDescriptorWithKey:@"createdDate" ascending:NO]];
User* user = [User getInstance];
NSDate *TwelveHoursAgo = [NSDate dateWithTimeIntervalSinceNow:-3600 * 12];
request.predicate = [NSPredicate predicateWithFormat:@"(servicePersonId == %@) AND (createdDate >= %@)", [NSNumber numberWithLong:user.userId], TwelveHoursAgo];
ordersTableViewController.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:super.managedObjectContext sectionNameKeyPath:@"orderPosition" cacheName:nil];
As you can see, this is making sections based on "orderPosition"
and ordering all the orders by "createdDate"
. But I need to order certain orders by "deliverDate"
Thanks
Upvotes: 1
Views: 499
Reputation: 2678
I can think of two ways around this problem.
Method One: Use a separate NSFetchedResultsController for each section. This way you can use a different search descriptor for each section. This ties some of the model details to your controller and means that if you plan to create a new status type you will need to modify your controller as well as your model.
The simplest way to implement this is to create an array of the different NSFetchedResultsControllers. The number of items in the array is the number of sections. Note, however, that doing this might result in empty sections in your table view. For example, if there aren't any accepted orders, you will probably still end up with the Accepted Orders section in your UITableView.
At a certain point, this can get complicated enough to warrant putting this code into its own custom results controller that manages a list of NSFetchedResultsControllers internally and expose an external interface similar or identical to an NSFetchedResultsController.
Method Two: Add a special field your model to use as a sort field then automatically update that field to keep the sort order the way you like it. For example, for orders with a status "new" you just store the order date in this field. For orders with the "accepted" status, you store the delivery date. For orders with the "delivered" status, you want to store the order date, but you want it to be in a reverse direction. The simplest way to implement this reversal in order is to store the order date multiplied by -1.
NSDate's are just wrappers around a simple primitive which stores the time interval between the represented date and January 1st, 2001. You can easily multiply that number by -1 using this code:
float interval = [orderDate timeIntervalSinceReferenceDate];
NSDate *reversedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:(interval * -1)];
Using the above code, an order date of 2013-10-31 02:03:20 results in a reversed date of 1988-03-03 21:56:48.
You will need to keep this special ordering field up to date by implementing a custom class for the Order entity if you haven't done so already, and writing custom setters for the order status and the dates involved to change this field when the fields it depends on change.
This second method seems hakish and entails denormalization but may be the better solution depending on your application and how you expect that application to change in the future.
Upvotes: 3