NSFetchedResultsController с датой как sectionNameKeyPath
Я разрабатываю приложение, которое использует Core Data. В одном UITableView я хочу отобразить список моих объектов, отсортированных по сохраненной дате объектов. Когда я это сделаю:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:@"date"
cacheName:nil];
Я получаю для каждого объекта новый раздел, потому что этот код также группирует даты в соответствии с секундами. Но мне нужен список объектов, сгруппированных по дате, но только по дням, месяцам и годам. Это возможно и как?
Большое спасибо за вашу помощь!!;)
Ответы
Ответ 1
Это должно сделать трюк для вас:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *rawDateStr = [[[self.fetchedResultsController sections] objectAtIndex:section] name];
// Convert rawDateStr string to NSDate...
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZ"];
NSDate *date = [formatter dateFromString:rawDateStr];
// Convert NSDate to format we want...
[formatter setDateFormat:@"d MMMM yyyy"];
NSString *formattedDateStr = [formatter stringFromDate:date];
return formattedDateStr;
}
[EDIT]
Jus увидел ваш комментарий и то, что вы пытаетесь достичь, вы можете создать переходный NSDate
атрибут (не постоянный), который отформатирован аналогично приведенному выше коду (т.е. без H: mm: ss ZZZZ) и использовать этот атрибут как ваше значение sectionNameKeyPath
.
Итак, в двух словах для объекта foo
, с атрибутами fooDate
и fooDateTransient
, вы должны:
-
Получите атрибут foo.fooDate
-
Преобразуйте его с помощью кода выше (или аналогичного) и назначьте результат NSDate
foo.fooDateTransient
-
Используйте fooDateTransient
как ваш sectionNameKeyPath
при создании объекта fetchedResultsController
.
PS: Я не тестировал это сам, но должен быть достоин!
Удачи,
Рог
Ответ 2
Отъезд: http://developer.apple.com/library/ios/#samplecode/DateSectionTitles/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009939
Он работает с месяцем и годом, но довольно легко заставить его работать с днем, месяцем и годом.
Ответ 3
Ниже приведено решение Swift 3 для сортировки по дате, но есть заголовки разделов, соответствующие отдельным дням.
- Добавить свойство переходного процесса, называемое
daySectionIdentifier
, вашей сущности в Core Data.
- Восстановите свой подкласс
NSManagedObject
. Удалите свойство для daySectionIdentifier
, которое может быть сгенерировано в Entity+CoreDataProperties.swift
.
-
В файл Entity+CoreDataClass.swift
добавьте следующий getter для daySectionIdentifier
:
// Transient property for grouping a table into sections based
// on day of entity date. Allows an NSFetchedResultsController
// to sort by date, but also display the day as the section title.
// - Constructs a string of format "YYYYMMDD", where YYYY is the year,
// MM is the month, and DD is the day (all integers).
public var daySectionIdentifier: String? {
let currentCalendar = Calendar.current
self.willAccessValue(forKey: "daySectionIdentifier")
var sectionIdentifier = ""
if let date = self.date as? Date {
let day = currentCalendar.component(.day, from: date)
let month = currentCalendar.component(.month, from: date)
let year = currentCalendar.component(.year, from: date)
// Construct integer from year, month, day. Convert to string.
sectionIdentifier = "\(year * 10000 + month * 100 + day)"
}
self.didAccessValue(forKey: "daySectionIdentifier")
return sectionIdentfier
}
-
В вашей реализации UITableViewController
добавьте следующий метод:
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var sectionTitle: String?
if let sectionIdentifier = fetchedResultsController.sections?[section].name {
if let numericSection = Int(sectionIdentifier) {
// Parse the numericSection into its year/month/day components.
let year = numericSection / 10000
let month = (numericSection / 100) % 100
let day = numericSection % 100
// Reconstruct the date from these components.
var components = DateComponents()
components.calendar = Calendar.current
components.day = day
components.month = month
components.year = year
// Set the section title with this date
if let date = components.date {
sectionTitle = DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .none)
}
}
}
return sectionTitle
}
- При построении
NSFetchedResultsController
вызовите инициализатор с "daySectionIdentifier"
как параметр sectionNameKeyPath
.
- Установите дескриптор сортировки
NSFetchedResultsController
в свой обычный простой атрибут "date"
. Важно отметить, что порядок сортировки, основанный на "date"
, будет соответствовать порядку сортировки на основе только что построенного идентификатора раздела.
Теперь вы должны иметь сводку таблицы, сгруппированную по секциям в день (например, "6 февраля 2017 года" ) и отсортированную по мелкозернистой дате.
Ответ 4
Я думаю, это было бы лучше.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// Replace DataClassObject with whatever object your using
DataClassObject *tempObject = [[sectionInfo objects] objectAtIndex:0];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"d MMMM yyyy"];
NSString *formattedDateStr = [formatter stringFromDate:tempObject.date];
[dateFormatter release]
return formattedDateStr;
}
Ответ 5
Я использовал @BoltClock a Unicorn и @Rog anwser, когда имел ту же проблему.
Просто добавленный переходный NSString * sectionTitle к моему управляемому объекту, использовал @ "sectionTitle" как sectionNameKeyPath и создал пользовательский геттер, например:
-(NSString *)sectionTitle
{
NSDate *_now = [NSDate date];
NSDate *_today = [_now dateByAddingTimeInterval: -86400.0];
NSDate *_yesterday = [_now dateByAddingTimeInterval: -172800.0];
NSDate *_thisWeek = [_now dateByAddingTimeInterval: -604800.0];
NSDate *_lastWeek = [_now dateByAddingTimeInterval: -1209600.0];
NSDate *_thisMonth = [_now dateByAddingTimeInterval: -2629743.0];
// if better precision required use something more sophisticated for month...
double today = [_today timeIntervalSince1970];
double yesterday = [_yesterday timeIntervalSince1970];
double thisWeek = [_thisWeek timeIntervalSince1970];
double lastWeek = [_lastWeek timeIntervalSince1970];
double thisMonth = [_thisMonth timeIntervalSince1970];
[self willAccessValueForKey:@"timestamp"];
double ts = [self.timestamp timeIntervalSince1970];
[self didAccessValueForKey:@"timestamp"];
NSString *title = @"";
if(ts >= today) title = NSLocalizedString(@"TODAY",nil);
else if (ts >= yesterday) title = NSLocalizedString(@"YESTERDAY",nil);
else if (ts >= thisWeek) title = NSLocalizedString(@"THIS WEEK",nil);
else if (ts >= lastWeek) title = NSLocalizedString(@"LAST WEEK",nil);
else if (ts >= thisMonth) title = NSLocalizedString(@"THIS MONTH",nil);
return title;
}