【问题标题】:NSFetchedResultsController custom sort not getting calledNSFetchedResultsController 自定义排序未被调用
【发布时间】:2011-06-14 22:58:16
【问题描述】:

我目前正在尝试使用 NSFetchedResultsController 从 Core Data 填充我的项目中的 UITableView。我正在使用带有比较器的自定义搜索(尽管我也尝试过选择器并且遇到了相同的问题):

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    /*
     Set up the fetched results controller.
    */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"objectName" ascending:YES comparator:^(id s1, id s2) {
            NSLog(@"Comparator");
      //custom compare here with print statement
    }];
    NSLog(@"Sort Descriptor Set");
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    [fetchRequest setSortDescriptors:sortDescriptors];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"firstLetterOfObject" cacheName:@"Objects"];
    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];
    if (![fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return fetchedResultsController;

当我进入这个选项卡时,我已经记录了整个程序,发现 NSFetchedResultsController 在获取时甚至没有进入比较器块。而是使用一些默认排序方法对其进行排序。

但是,如果我删除并添加一个带有 objectName 的对象,它就会进入比较器块并正确地对表进行排序。

为什么 NSFetchedResultsController 在托管对象模型更改之前不使用比较器进行排序?

注意:我也尝试过关闭缓存和/或在 viewDidLoad: 中执行提取,但似乎我提取多少次并不重要,而是何时提取。出于某种原因,它仅在对象模型更改后才使用我的排序。

【问题讨论】:

    标签: iphone objective-c cocoa-touch core-data nsfetchedresultscontroller


    【解决方案1】:

    我能想到几件事。首先,尽管这可能不是您的问题,但您不能对瞬态属性进行排序。但更有可能的是,在由 SQL 存储支持的模型中进行排序时,比较器被“编译”为 SQL 查询,并且并非所有 Objective-C 函数都可用。在这种情况下,您需要在执行 fetch 后在内存中进行排序。

    编辑:请参阅此 doc,特别是 Fetch Predicates 和 Sort Descriptors 部分。

    【讨论】:

    • 它们不是临时属性,但您的其他建议肯定看起来可能是问题所在。唯一的问题是我依靠 fetchedresultscontroller 向表视图提供部分名称等,因此每次在内存中排序都会很困难(我认为)。你会建议如何去做?我的另一个问题是为什么在更改对象模型后比较器块会起作用?谢谢!
    • 其实这里更普遍的问题是我在我的表格视图中实现了部分,以及一个部分索引。我将任何以数字开头的对象放在“123”部分(这可行),但我希望该部分像 iPod 应用程序一样位于底部。根据 Apple 的应用程序,数字应该是 sectionIndex 中的最后一个选项(我使用 UILocalizedIndexedCollat​​ion 来生成部分索引)。然而,似乎没有办法获取这些部分,以便数字排在最后。你知道比自定义排序更可靠的方法吗?
    • 只是一个猜测,但我认为比较器块在对象模型更改后工作,因为图形已经在内存中。但这只是一个猜测。我相信你手动排序的方式是继承 NSArrayController,所以你会失去 NSFetchedResultsController 的好处。但是,正如您所说,根本问题是您要将数字排序到底部。在我的脑海中,我会说在你的对象上创建一个排序顺序属性并使用它,但是我没有使用排序描述符完成足够的自定义排序。
    • 再次感谢 Don,您似乎对文档中的发现有所了解。根据我发现的另一个 stackoverflow 问题,我还通过将所有内容加载到数组中并使用它来填充列表并确定部分来实现这一点。一切都很好。
    • 太棒了!真高兴你做到了。我在 Cocoa Is My Girlfriend 上也发现了这一点,这也建议使用 sortOrder 属性:cimgf.com/2010/06/05/re-ordering-nsfetchedresultscontroller
    【解决方案2】:

    我看到了同样的问题,解决它的方法是修改一个对象,保存更改,然后将其恢复为原始值并再次保存。

        // try to force an update for correct initial sorting bug
    NSInteger count = [self.fetchedResultsController.sections count];
    if (count > 0) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:0];
        count = [sectionInfo numberOfObjects];
        if (count > 0) {
            NSManagedObject *obj = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
            NSString *name = [obj valueForKey:@"name"];
            [obj setValue:@"X" forKey:@"name"];
            // Save the context.
            [self saveContext];
            [obj setValue:name forKey:@"name"];
            // Save the context.
            [self saveContext];
        }
    }
    

    【讨论】:

      【解决方案3】:

      抱歉,您是否错过了代码 sn-p 的最后提取部分?:

      NSError *error;
      BOOL success = [aFetchedResultsController performFetch:&error];
      

      也不要忘记发布请求:

      [fetchRequest release];
      

      【讨论】:

      • 不,我只是没有将它包含在 sn-p 中。如果这样更清楚,我已经包含了整个方法。
      猜你喜欢
      • 1970-01-01
      • 2014-08-16
      • 2022-12-14
      • 1970-01-01
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-02
      相关资源
      最近更新 更多