【问题标题】:Fetch in set with order与订单一起取货
【发布时间】:2014-07-13 13:47:31
【问题描述】:

我的核心数据对象如下所示:

Person
-------
presonId
name

现在假设我有一个personsIds 数组,我想获取所有Person 对象,其中包括这个personsIds 数组。

所以我的获取请求将是:

NSArray *personsIds = [self getPersonsIds];  

// fetch all persons with ids in personsIds
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
request.predicate = [NSPredicate predicateWithFormat:@"presonId in %@", personsIds];  
NSArray *results = [self.context executeFetchRequest:request error:&anyError];

现在我的问题是:
personsIds 的顺序很重要,我希望results 数组的顺序相同。

我无法处理personId 数组,无法对其进行排序或其他任何东西..

注意personsIds 数组可能比results 数组包含更多的对象

【问题讨论】:

    标签: ios objective-c core-data nsfetchrequest


    【解决方案1】:

    您可以使用NSSortDescriptor对获取请求结果进行排序:

    NSSortDescriptor *sort1 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSSortDescriptor *sort2 = [[NSSortDescriptor alloc] initWithKey:@"personId" ascending:YES];
    
    request.sortDescriptors = [NSArray arrayWithObjects:@[sort1, sort2]];
    

    排序描述符的外观取决于您希望如何对结果进行排序。这取决于您的 personIds 数组的排序方式。

    如果您无法以如此笼统的方式描述排序,则需要遍历结果并手动对其进行排序。

    【讨论】:

    • 那个问题是我的 personId 数组没有排序,但它的顺序很重要,所以我无法排序。我需要结果与我的 personId 数组的顺序相同。也许我不应该在这里使用排序这个词。我会更新我的问题
    • 然后您需要自己进行排序,方法是循环遍历结果并像 personIds 数组一样进行排序。
    【解决方案2】:

    正如 Cornelius 所说,您使用排序描述符。在您的情况下,排序被定义为“按其他列表的顺序”。所以我们需要一种方法将 personId 映射到“原始列表中的索引”,然后对其进行排序。让我们构建一个NSComparator 来帮助我们(这些都没有经过实际测试,但应该可以编译):

    NSComparator comparatorForOriginalList(NSArray *list, NSString *key) {
      NSArray *order = [list valueForKey:key]; // The personIds in the order we want
      return ^(id obj1, id obj2) {
         // We're passed personIds, map them to their locations
        NSUInteger idx1 = [order indexOfObject:obj1];
        NSUInteger idx2 = [order indexOfObject:obj2];
    
        // And do the surprisingly tedious task of comparing them (why is this still so hard?)
        if (idx1 > idx2) {
          return (NSComparisonResult)NSOrderedDescending;
        }
        if (idx1 < idx2) {
          return (NSComparisonResult)NSOrderedAscending;
        }
        return (NSComparisonResult)NSOrderedSame;
      };
    }
    

    给定一个列表和一个键,这将返回一个函数,该函数将列表中该键的第一个对象的值的位置与第二个对象的位置进行比较,并告诉您它们是否按顺序排列。

    有了这些,创建排序描述符就很容易了:

    NSString *key = @"personId";
    NSComparator comparator = comparatorForOriginalList(originalList, key);
    NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:key
                                               ascending:YES
                                              comparator:comparator];
    

    【讨论】:

    • 这个不错,没想到:)
    • 我不认为我可以将这种比较器与核心数据一起使用,当我尝试得到异常时:“不支持的 NSSortDescriptor(不支持比较器块)”
    • 我也尝试在 fetch 之后进行内存排序,但这需要很长时间,大约 3 分钟才能处理约 4000 个对象。
    • 这种排序是 O(n^2),所以它的扩展性很差(虽然 4000 条记录的 3 分钟似乎过多,所以你可能需要做一些优化工作)。为了改善这一点,您可以尝试创建一个 personId->index 字典,以便以后查找更快。或者将您的结果放入 personId->record 字典中,以便按需查找。
    • 当然不使用 SQL。某些配置中的 Core Data 构建在 SQL 之上,但它不需要它,您不能依赖它或直接访问底层 SQL 存储。
    猜你喜欢
    • 2021-09-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 2011-11-27
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 2020-02-08
    相关资源
    最近更新 更多