如何通过 valueForKey 从 fetch 中对数组进行排序

Posted

技术标签:

【中文标题】如何通过 valueForKey 从 fetch 中对数组进行排序【英文标题】:how to sort array from fetch by valueForKey 【发布时间】:2014-06-15 00:23:48 【问题描述】:

我有一个 fetchResultController,它通过运行多个方法来编译一个数组。最后的单元格显示名称和数字(排名)。我想从表格视图中取出单元格并按数字(升序)对它们进行排序。我已经在 frc 中尝试过 nssortdescriptor,但是当我尝试调用“排名”时遇到了问题,因为它不是我正在获取的实体的键路径。有没有一个地方可以截取从 frc 出来的这个数组以按 valueForKey:@"ranking" 排序?我将如何实现这种排序?

它循环创建 valueForKey 的方法在这里:

- (NSExpressionDescription*) rankingExpressionDescriptionForTags:(NSSet*)itemToTag

    NSPredicate* p2 = [NSPredicate predicateWithFormat:@"SUBQUERY(itemToTag,$t,$t.tagName IN %@).@count > 0",[itemToTag valueForKey:@"tagName"]];
    NSExpression* rankExpresion = [(NSComparisonPredicate*)p2 leftExpression];
    NSExpressionDescription* rankExpDesc = [[NSExpressionDescription alloc] init];
    rankExpDesc.name = @"ranking";
    rankExpDesc.expression = rankExpresion;
    rankExpDesc.expressionResultType = NSInteger64AttributeType;

    return rankExpDesc;


- (NSExpressionDescription*) objectIDExpressionDescription

    NSExpressionDescription* expDesc = [[NSExpressionDescription alloc] init];
    expDesc.name = @"objectID";
    expDesc.expressionResultType = NSObjectIDAttributeType;
    expDesc.expression = [NSExpression expressionForEvaluatedObject];
    return expDesc;


- (NSFetchRequest*) rankingRequestForItem:(Item*)item 

    NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Item"];
    NSPredicate* p = [NSPredicate predicateWithFormat:@"SELF != %@",item.objectID];
    r.resultType = NSDictionaryResultType;


    r.propertiesToFetch = @[[self objectIDExpressionDescription],@"itemName",
                            [self rankingExpressionDescriptionForTags:[item mutableSetValueForKey:@"itemToTag"]]];


    r.predicate = p;
    r.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES]];


    return r;

带有单元格配置的 frc 在这里:

- (NSFetchedResultsController *)fetchedResultsController

    if (_fetchedResultsController != nil) 
        return _fetchedResultsController;
    

    NSLog(@"selected item: %@, itemToTag: %@",selectedItem.itemName,[selectedItem.itemToTag valueForKey:@"tagName"]);
    NSFetchRequest *fetchRequest = [self rankingRequestForItem:selectedItem];
    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".


    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) 

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    

    return _fetchedResultsController;



- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath

    NSDictionary *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"%@ - %@",[item valueForKey:@"itemName"],[item valueForKey:@"ranking"]];

感谢您的帮助!

【问题讨论】:

【参考方案1】:

正如我解释的HERE,没有办法(AFAIK)根据ranking 表达式进行排序。您必须在内存中对结果进行排序,从而完全不需要 FRC。

只需在给定上下文上执行请求并在内存中排序:

NSError* error = nil;
NSFetchRequest* r = [self rankingRequestForItem:selectedItem];
NSArray* results = [context executeFetchRequest:r error:&error];
NSSortDescriptor* sd = [NSSortDescriptor sortDescriptorWithKey:@"ranking" ascending:NO];
results = [results sortedArrayUsingDescriptors:@[sd]];

results 数组现在将保存您的排序信息,将其用作表格的数据源。 将results 存储在视图控制器属性中,例如:

self.results = results;

例如,此代码可能会出现在您的 viewDidLoad 方法中。

在您访问 FRC 以获取对象的任何地方,您现在都可以访问表数据源以获取该信息(假设您只有 1 个部分):

NSIndexPath* someIndexPath = //some index path you might get as parameter
[self.results objectAtIndex:someIndexPath.row]; //return NSDictionary

【讨论】:

谢谢丹。上面的方法在 numberOfRowsInSection 中,对吧?从那里它遍历方法,但是当它点击'results = [results sortedArrayUsing ...'时我得到'无法识别的选择器发送到实例'(我添加了@“ranking”)。我离这儿很远吗?如果在表数据源中生成了“结果”,我应该使用什么 configureCell 来识别它? 不,这会构建您的数据源(就像您现在在 fetchedResultsController 方法中拥有的代码一样)。看我的编辑。您应该学习如何调试代码,或者至少阅读返回的完整错误描述。 “无法识别的选择器发送到实例”是对错误的部分描述,在一般情况下,除非您更好地解释错误,否则没有人可以帮助您。当某个方法无法按您预期的方式工作时,请阅读其文档(如 THIS) 有效!谢谢丹,这很棒。只是为了确认一下,大部分代码(除了 nsindex 之外的所有代码......)都在 viewDidLoad 中吗?它现在在那里工作。非常感谢您的帮助! @user3411663 是的,但它可以转换为“延迟加载”,就像实现原始fetchedResultsController 属性一样...

以上是关于如何通过 valueForKey 从 fetch 中对数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中,对于 AnyObject,我如何 setValue() 然后调用 valueForKey()

十二:objectForKey与valueForKey区别简单分析

如何通过ajax fetch api响应将从laravel控制器接收到的数据发送到另一个页面

Swift 3“任何”类型的值没有成员“valueForKey”

使用 fetch、cors 时如何从 json API 获取属性?

IOS开发之——objectForKey与valueForKey在NSDictionary中的差异