I have a UITableView
that is blank to start with but gets populated by the user entering in some information. The user clicks on a button in the UINavigationBar
, gets taken to another View Controller
and fills in text into a UITextField
and selects a date from the UIDatePicker
. When the user presses Save
, the UITableView
is updated with the use of NSFetchedResultsController
and Core Data
.
Within the UITableView
, the date is represented by the section
header titles, while the UITextField
text is represented in the actual cells
.
The NSFetchRequest is ordered by date and then alphabetically by person.
Issue
It's not a common scenario, but if I add in an entry in a New York Timezone with Person name A, and then add in another entry with Person name B with the same date, it will show A and then B in that order.
If I change to a London timezone and add in another entry with person name A and the same date, this new entry is now below B.
I understand why this is happening but I'm not sure what to do to fix it.
Code
This is my NSFetchReqest
:
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
if ([self.timelineSearchBar.text length] > 0) {
NSPredicate *predName = [NSPredicate predicateWithFormat:@"whoBy.name CONTAINS[c] %@", self.timelineSearchBar.text];
NSPredicate *predOccasion = [NSPredicate predicateWithFormat:@"occasion.title CONTAINS[c] %@", self.timelineSearchBar.text];
NSPredicate *predSubOccasion = [NSPredicate predicateWithFormat:@"subevent.title CONTAINS[c] %@", self.timelineSearchBar.text];
NSPredicate *compPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predName, predOccasion, predSubOccasion]];
[fetchRequest setPredicate:compPredicate];
}
// Sorting by date and by name.
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"dates.dateOfEvent" ascending:NO];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"whoBy.name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
fetchRequest.sortDescriptors = @[sort, sortDescriptor];
fetchRequest.fetchBatchSize = 20;
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"sectionDateFormatter" cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
The sort descriptor is sorting by date and then name, so it makes sense that this is happening.
Here's my saving method:
- (IBAction)save:(id)sender
{
// Start by obtaining the managedObjectContext.
NSManagedObjectContext *context = [self managedObjectContext];
// Insert a new transaction
Transaction *transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];
Person *enteredPerson = (Person *)[Person personWithName:self.nameTextField.text inManagedObjectContext:context];
transaction.whoBy = enteredPerson;
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:self.datePicker.date];
NSDate *selectedDate = [cal dateFromComponents:components]; */
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:self.datePicker.date];
NSDate *selectedDate = [cal dateFromComponents:components];
Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context];
transaction.dates = date;
// Save the ManagedObjectContext
NSError *error = nil;
if (![context save:&error])
{
// Error
}
[self dismissViewControllerAnimated:YES completion:nil];
}
I'm not doing anything fancy with timezones, but if I set the NSDateComponent
, NSCalendar
and/or UIDatePicker
to the [NSTimeZone localTimeZone]
, I get the same behaviour.
Essentially, I'd like to keep the sorting by date and then by name, but within each date, I'd like to sort just by name. It's all the same date (but just created with different timezones), so it treats it as a later time on the same time. I'm not making any use of timing.
Save your dates as dates in the same time zone, e.g. by transposing the date to GMT if necessary. You can add the time zone information to your data model or change the date display on the fly based on runtime settings.