I am using Core Data with an NSFetchedResultsController to display dates in a table view. Upon fetch I want these date objects sorted by the closest upcoming month/day to today while ignoring the year, preferably (if possible) without having to store the fetched results in an array and being forced to perform a separate sort operation on that array. That's the basic idea, the rest is context.
My NSManagedObject subclass Date
has 2 attributes:
Date.date -> 1986-02-06 08:00:00 +0000 // the stored date of type Date
Date.equalizedDate -> 02/06 // computed from date ignoring year of type String
If I use NSSortDescriptor(key: "date", ascending: true)
on the fetched results controller, then the dates in the table view are sorted by year (not what I want):
Date.date 1978-06-23 07:00:00 +0000 // 1978 = #1
Date.date 1986-02-06 08:00:00 +0000 // 1986 = #2
Date.date 1991-07-26 07:00:00 +0000 // 1991 = #3
If I use NSSortDescriptor(key: "equalizedDate", ascending: true)
I can get one step closer by ignoring the year and showing proper ascension but it's not compared to today's date:
Date.date 1986-02-06 08:00:00 +0000 // 02/06 = #1 (February 6th)
Date.date 1978-06-23 07:00:00 +0000 // 06/23 = #2 (June 23rd)
Date.date 1991-07-26 07:00:00 +0000 // 07/26 = #3 (July 26th)
If, for example, today was April 5th, then I would want the fetched results to be fetched and displayed as follows:
// Today is April 5th
Date.date 1978-06-23 07:00:00 +0000 // 06/23 = #1 (June 23rd)
Date.date 1991-07-26 07:00:00 +0000 // 07/26 = #2 (July 26th)
Date.date 1986-02-06 08:00:00 +0000 // 02/06 = #3 (February 6th)
Currently, the only way for me to accomplish this is by storing the fetched results controller results in an array, performing a comparison upon the array, and using the array instead of my fetched results controller for the data source of my table view rows and cells:
// fetchedResults = [Date] <- stored Date objects from fetch
for fetchedDate in fetchedResults {
// formatDateIntoString changes 2015-10-26 05:43:22 +0000 into 10/26
if fetchedDate.equalizedDate < NSDate().formatDateIntoString() {
fetchedResults.removeAtIndex(0)
fetchedResults.append(fetchedDate)
} else {
break
}
}
return fetchedResults
I would prefer to omit this extra layer of logic because it not only eliminates the entire purpose of performance of a fetched results controller but it also gives me wonky troubles and wrong index paths when implementing swipe to delete (link for reference). I know that comparators and selectors don't work for fetched result controllers.
Is there any way to work around this issue?
I think an easier solution is to simply modify your equalizedDate
attribute as follows:
First, make it into a transient property.
Second, make it behave dynamically according to the current date. You can make this attribute very simple, but would then need to write more code to interpret it, or you can try to return something you can use directly.
A simple solution is to return just the offset from todays date (a number from 0 to 365). You would have to add functionality to return the correct date string (or date) based in this number and today's date.
An IMO better solution is to return a date with with a correctly normalized year. You would set the current and future dates to the current year, and all past dates to the next year, also resulting in 365 (366) dates.
You could now easily sort by the transient property, or even use it for sectioning.