NSSortDescriptor按上次消息时间戳排序对话

时间:2016-01-03 17:20:12

标签: ios swift uitableview core-data nssortdescriptor

我是NSSortDescriptor的新手,所以任何提示都受到高度赞赏。

我有UITableView,其中包含对话。每个对话都可以有多条消息。消息显示在另一个视图中。它基本上就像iMessage。 在Conversation-TableView中,我想按最新消息订购对话。

为简单起见,我绘制了以下抽象模型: enter image description here

每个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>'

3 个答案:

答案 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;