NSFetchedResultsController с датой в виде sectionNameKeyPath
Я разрабатываю приложение, которое использует основные данные. В одном UITableView я хочу отобразить список моих сущностей, отсортированных по сохраненной дате объектов. Когда я делаю это:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:@"date"
cacheName:nil];
Я получаю для каждого объекта новый раздел, потому что этот код группирует даты в соответствии с секундами. Но мне нужен список объектов, сгруппированных по датам, но только по дням, месяцам и годам. Возможно ли это и как?
Большое Спасибо за вашу помощь!! ;)
5 ответов:
Это должно сделать трюк для вас:
- (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: Я не проверял это сам, но стоит попробовать!
Удачи, Rog
Ниже приводится быстрое решение 3 для сортировки по дате, но с заголовками разделов, соответствующими отдельным дням.
- добавьте переходное свойство
daySectionIdentifier
к вашей сущности в основных данных.- Регенерируйте свой подкласс
NSManagedObject
. Удалите свойство дляdaySectionIdentifier
, которое может быть сгенерировано вEntity+CoreDataProperties.swift
.В файл
Entity+CoreDataClass.swift
добавьте следующий геттер дляdaySectionIdentifier
:// Transient property for grouping a table into sections based // on day of entity's 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") и отсортированное по мелкозернистым дата.
Я думаю, что это будет лучше.
- (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; }
Я использовал единорога @BoltClock и anwser @Rog, когда у меня была та же проблема. Просто добавил временный 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; }