NSSortDescriptor сортирует разговоры по отметке времени последнего сообщения

Я новичок в NSSortDescriptorпоэтому любые подсказки очень ценятся.

У меня есть UITableView, который содержит разговоры. Каждая беседа может иметь несколько сообщений. Сообщения отображаются в другом представлении. Это в основном как iMessage. В Conversation-TableView я хочу упорядочить разговоры по самым последним сообщениям.

Для простоты я нарисовал следующую абстрактную модель: введите здесь описание изображения

Каждый conversation имеет набор messages. У каждого message есть date.

Когда я получаю conversation (используя NSFetchedResultsController), я хочу, чтобы они упорядочены по date свойства messages. Я думал, что это должно быть довольно просто, просто используя вычисляемые свойства, но это не работает.

Я попытался использовать ключевой путь:

request.sortDescriptors = [NSSortDescriptor(key: "messages.date", ascending: false)]

... но это вылетает с *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here.

Изменить: относительно возможного дублирования.

Когда я пытаюсь применить это ко всем элементам NSSet, я получаю следующую ошибку: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath ALL messages.date not found in entity <NSSQLEntity Conversation id=1>'

Используя следующий дескриптор сортировки:

request.sortDescriptors = [NSSortDescriptor(key: "ALL messages.date", ascending: false)]

person Chris    schedule 03.01.2016    source источник
comment
Возможный дубликат основных данных: NSPredicate для отношений «многие ко многим». (ключ to-many здесь не разрешен)   -  person chedabob    schedule 03.01.2016
comment
Я нашел это. Но это для NSPredicate, а не NSSortDescription. Это работает, только если вы хотите фильтровать вещи, а не сортировать, к сожалению.   -  person Chris    schedule 03.01.2016
comment
Это все еще применимо. messages является NSSet, поэтому у него нет свойства date для сортировки.   -  person chedabob    schedule 03.01.2016
comment
Пробовал, но сравнить не с чем? Я обновил исходный вопрос кодом, который пробовал. Не могли бы вы объяснить мне, как использовать это для NSSortDescriptor?   -  person Chris    schedule 03.01.2016


Ответы (2)


Создайте категорию в NSDate, которая возвращает временной интервал с начала дня для текущего календаря и часового пояса, а затем используйте этот временной интервал для сортировки.

@interface NSDate (CBVAdditions)


- (NSTimeInterval)cbvTimeIntervalSinceStartOfDay;


@end

@implementation NSDate (CBVAdditions)


- (NSTimeInterval)cbvTimeIntervalSinceStartOfDay
{

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];


    NSDateComponents *dateComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:self];


    [dateComponents setCalendar:calendar];

    [dateComponents setTimeZone:timeZone];

    NSInteger hoursComponent = dateComponents.hour * 3600;

    NSInteger minutesComponent = dateComponents.minute * 60;

    double secondsComponent = dateComponents.second;

    NSTimeInterval toReturn = hoursComponent + minutesComponent + secondsComponent;

    return toReturn;

}

Затем вы можете использовать NSSortDescriptor с таким ключом, как @"dateProperty.cbvTimeIntervalSinceStartOfDay", чтобы выполнить фактическую сортировку. Например, я показываю класс Event и некоторый код, выполняющий сортировку.

@interface Event : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSDate *eventDate;

@end

@implementation Event

- (NSString *)description
{
    NSString *desc = [NSString stringWithFormat:@"%@, name = %@, eventDate = %@",[super description], self.name, [self.eventDate descriptionWithLocale:[NSLocale currentLocale]]];
    return desc;
}
@end

Event *e1 = [Event new];

e1.eventDate = [NSDate date];

e1.name = @"e1";

Event *e2 = [Event new];

e2.eventDate = [NSDate dateWithTimeIntervalSinceNow:(-1 * 22 * 3600)];

e2.name = @"e2";

Event *e3 = [Event new];

e3.eventDate = [NSDate dateWithTimeIntervalSinceNow:3600];

e3.name = @"e3";

NSArray *events = @[e1,e2,e3];

NSLog(@"Events = %@", events);

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"eventDate.cbvTimeIntervalSinceStartOfDay" ascending:YES];

NSArray *sortedEvents = [events sortedArrayUsingDescriptors:@[sortDescriptor]];

NSLog(@"Sorted Events = %@", sortedEvents);

код представил следующий вывод:

2013-01-15 15:50:54.221 DateSortingFun[67319:c07] Events = (
    "<Event: 0x717b050>, name = e1, eventDate = Tuesday, January 15, 2013, 3:50:54 PM Mountain Standard Time",
    "<Event: 0x717b620>, name = e2, eventDate = Monday, January 14, 2013, 5:50:54 PM Mountain Standard Time",
    "<Event: 0x717b650>, name = e3, eventDate = Tuesday, January 15, 2013, 4:50:54 PM Mountain Standard Time" ) 


2013-01-15 15:50:54.222 DateSortingFun[67319:c07] Sorted Events = (
    "<Event: 0x717b050>, name = e1, eventDate = Tuesday, January 15, 2013, 3:50:54 PM Mountain Standard Time",
    "<Event: 0x717b650>, name = e3, eventDate = Tuesday, January 15, 2013, 4:50:54 PM Mountain Standard Time",
    "<Event: 0x717b620>, name = e2, eventDate = Monday, January 14, 2013, 5:50:54 PM Mountain Standard Time" )
person Akash    schedule 04.01.2016
comment
Спасибо, но вы упускаете связь 1:n между разговорами и сообщениями (которая на самом деле содержит дату). Проблема в том, что я не могу получить доступ к свойству даты в массиве сообщений из беседы. - person Chris; 04.01.2016

Что вам нужно сделать, так это добавить в разговор атрибут дата последнего сообщения. Это позволит вам эффективно сортировать разговоры.

Это то, что называется денормализацией. Вы должны убедиться, что это поле дата последнего сообщения актуально. Есть много подходов. Один из них — переопределить willSave() в диалоге и проверить, есть ли изменения в отношениях Сообщения или в каких-либо Сообщениях. любые дефекты объектов. Если что-то изменилось, вы должны обновить атрибут дата последнего сообщения беседы.

В разделе Как создавать эффективные модели данных в главе Производительность нашей книги содержится более подробная информация. https://www.objc.io/books/core-data/

person Daniel Eggert    schedule 04.01.2016