核心数据和 NSSortDescriptor 未根据基于 NSString 的第三个描述符排序

Posted

技术标签:

【中文标题】核心数据和 NSSortDescriptor 未根据基于 NSString 的第三个描述符排序【英文标题】:Core Data and NSSortDescriptor not sorting according to third descriptor based on NSString 【发布时间】:2013-06-27 02:32:25 【问题描述】:

我有一个 NSFetchRequest 正在获取一个名为“Player”的实体,我希望结果按以下顺序按 3 个属性排序:

    名为“sendingoffOffence”的属性是否为 nil “team.homeMatch”实体中的关系是否为零 我希望“数字”属性中的字符串按升序排序。

基本上,我希望所有有红牌的球员(“sendingOffence”不为零)出现在列表的顶部,然后根据球员是否在主队进行排序,然后最终将进攻组中的一组球员按球衣号码排序。

因此,我在获取请求中使用以下代码:

// Set the entity for the fetch request
NSEntityDescription *entity = [NSEntityDescription
                               entityForName:@"Player"
                               inManagedObjectContext:self.match.managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"match == %@", self.match];
[fetchRequest setPredicate:predicate];

// Sort the results

// Sort according to whether the user has a red card / sendingOffOffence
NSSortDescriptor *hasRedCard = [[NSSortDescriptor alloc] initWithKey:@"sendingoffOffence" ascending:NO];

// Sort according to whether the user is on the home team or not
NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:@"team.homeMatch" ascending:NO];

// Sort according to the player's jersey numbers
NSSortDescriptor *number     = [[NSSortDescriptor alloc] initWithKey:@"number" ascending:YES selector:@selector(localizedStandardCompare:)];

[fetchRequest setSortDescriptors:@[hasRedCard, isHomeTeam, number]];

// Set the amount of records to retrieve from the database
[fetchRequest setFetchBatchSize:20];

NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc]
     initWithFetchRequest:fetchRequest
     managedObjectContext:self.match.managedObjectContext
     sectionNameKeyPath:nil
     cacheName:@"MatchCache"]

但是,当我执行上述代码时,我得到以下结果:

这个排序顺序是错误的,因为我希望以下顺序出现在红牌部分:

11 - 主页 12 - 主页 0 - 离开 11 - 离开 21 - 离开

在黄牌区:

1 - 主页 2 - 主页 99 - 主页 1 - 离开 31 - 离开

看起来黄牌部分排序正确,但红牌部分表现出非常奇怪的行为,使其看起来根本没有得到排序。

我很困惑为什么红牌部分无法正确排序 - 有什么想法吗?我应该只在内存中对这些对象进行排序,而不是依靠核心数据来获得我喜欢的顺序吗?

请注意,这是一个带有 SQL 支持的持久性存储的核心数据应用程序。

更新

以下是核心数据在我的 fetch 中使用的 SQL 语句:

CoreData: annotation: fetch using NSSQLiteStatement <0x11c77cd0> on entity 'SPlayer' with 
sql text 'SELECT t0.Z_ENT, t0.Z_PK FROM ZFSMANAGEDOBJECT t0 LEFT OUTER JOIN ZSTEAM t1 ON 
t0.ZTEAM = t1.Z_PK WHERE ( t0.ZMATCH1 = ? AND  t0.Z_ENT = ?) ORDER BY 
t0.ZSENDINGOFFOFFENCE DESC, t1.ZHOMEMATCH DESC, t0.ZNUMBER COLLATE NSCollateFinderlike '

【问题讨论】:

Turn on SQL debugging 并确保它正在生成您期望的 SQL。您可以调高调试级别,使其除了记录它发送的 SQL 之外,还记录它接收的数据。 您的托管对象上下文是否已保存?您确定您的标签不只是显示不正确吗? 我开启了SQL调试,添加了上面的SQL命令。我没有错误地显示项目,因为我的 FetchedResultsController 中的数组是未正确排序的东西。 你们是如何实现localizedCompare:的? @tilo 我正在使用作为 NSString 类一部分的本地化StandardCompare: 方法:developer.apple.com/library/mac/documentation/Cocoa/Reference/… 【参考方案1】:

这是未正确应用的行(对于 RED 卡盒):

NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:@"team.homeMatch" ascending:NO];

如果没有看到您的数据模型和一些示例数据,很难说为什么不能正确排序。我会假设这将首先放置 NIL 值,然后是适当的值(因此排序升序 NO 会做它在黄色卡片盒中所做的事情)。

如果我处于这种情况,我会检查我对排序顺序和这些 team.homeMatch 属性的假设。做一个测试,这是唯一的排序描述。

然后关注红/黄卡条件的不同之处。

【讨论】:

谢谢 Jess - 所以看起来当“sendingoffOffence”不为空时,其他排序描述符无法应用,但当它为空时它们可以正常工作。【参考方案2】:

我们没有像这样检查它的 NSFetchedResultsController....

NSEntityDescription *entity = [NSEntityDescription
                               entityForName:@"Player"
                               inManagedObjectContext:self.match.managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"match == %@", self.match];
[fetchRequest setPredicate:predicate];

// Sort the results

// Sort according to whether the user has a red card / sendingOffOffence
NSSortDescriptor *hasRedCard = [[NSSortDescriptor alloc] initWithKey:@"sendingoffOffence" ascending:NO];

// Sort according to whether the user is on the home team or not
NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:@"team.homeMatch" ascending:NO];


[fetchRequest setSortDescriptors:@[hasRedCard, isHomeTeam]];

// Set the amount of records to retrieve from the database
[fetchRequest setFetchBatchSize:20];

NSArray *resultArray = [self.match.managedObjectContext executeFetchRequest:request error:&error];


NSSortDescriptor *number     = [[NSSortDescriptor alloc] initWithKey:@"number" ascending:YES selector:@selector(localizedStandardCompare:)];
    NSArray *sortedArray = [resultArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:number, nil]];

【讨论】:

以上是关于核心数据和 NSSortDescriptor 未根据基于 NSString 的第三个描述符排序的主要内容,如果未能解决你的问题,请参考以下文章

NSSortDescriptor 对核心数据获取请求没有影响

用于核心数据一对多关系的 NSSortDescriptor

使用 NSSortDescriptor 按时间错误排序(带有核心数据)

核心数据 - 可以使用 NSSortDescriptor 中的块对 TableView 进行排序吗?

NSSortDescriptor 按核心数据对多关系中的项目数排序

执行获取请求时,我必须在核心数据中提供 NSSortDescriptor 吗?