我是NSSortDescriptor
的新手,所以任何提示都受到高度赞赏。
我有UITableView
,其中包含对话。每个对话都可以有多条消息。消息显示在另一个视图中。它基本上就像iMessage。
在Conversation-TableView中,我想按最新消息订购对话。
每个conversation
都有一组messages
。每个message
都有date
。
当我提取conversation
(使用NSFetchedResultsController
)时,我希望它们按属性date
的{{1}}排序。
我认为只需使用计算属性就可以很容易,但这不起作用。
我尝试使用密钥路径:
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>'
答案 0 :(得分:0)
在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" )
答案 1 :(得分:0)
您要做的是在对话中添加最后一条消息日期属性。这样您就可以有效地对对话进行排序。
这就是所谓的非规范化。您需要确保此上次消息日期字段是最新的。有很多方法。一种是覆盖对话中的willSave()
,并检查消息关系或任何消息是否有变化 - 在检查时,您需要一定不要触发任何对象的故障。如果有任何更改,您可以更新对话的最后一条消息日期属性。
本书性能一章中的如何构建高效数据模型部分详细介绍了该内容。 https://www.objc.io/books/core-data/
答案 2 :(得分:-1)
NSInteger type;
NSDate* timestamp;
NSString* username;
NSString* session;
NSString* body;
NSFetchRequest * req = [[NSFetchRequest alloc] init];
[req setEntity:[NSEntityDescription entityForName:@"Message"
inManagedObjectContext:context]];
[req setPredicate:[NSPredicate predicateWithFormat:@"conversation == %@",
self]]; /* did that from a Conversation object.. */
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"sent_date"
ascending:NO];
[req setSortDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
NSError * error = nil;
NSArray * messages = [context executeFetchRequest:req error:&error];
[req release];
if ([messages count] > 0) { /* sanity check */
return [messages objectAtIndex:0];
}
return nil;