2012-04-20 5 views
4

Я пытаюсь сортировать результат NSFetchRequest с помощью NSSortdescriptor, используя ключ, указывающий на значение NSDate. Результаты моей выборки получаются абсолютно случайными без какой-либо ясной причины.NSSortdescriptor неэффективен при извлечении результата из NSManagedContext

NSManagedObjectContext, который я использую, обновляется с сохранением из вложенного дочернего контекста, созданного в подклассе NSOperation. Я знаю, что все это сделано успешно, потому что я могу получить все данные, необходимые из основного (основного) контекста. Извлечение из него просто не сортируется по дате!

Странно, что есть; предикаты для выбора объектов (так называемые «Tweet») между двумя датами прекрасно работают!

Вот код, чтобы проиллюстрировать мою проблему:

NSSortDescriptor* timeDescriptor = [NSSortDescriptor 
             sortDescriptorWithKey:@"time" 
             ascending:NO 
             selector:@selector(compare:)]; 

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Tweet"]; 
[request setSortDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]]; 

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"((time >= %@) AND (time <= %@))",startDate,endDate]; 
[request setPredicate:predicate]; 

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[context setParentContext:[[NSApp delegate] managedObjectContext]]; 
[context performBlock:^{ 
    NSError* error = nil; 
    NSArray* results = nil; 

    results = [context executeFetchRequest:request error:&error]; 
    // Results here are not ordered correctly 

    // 2nd try sorting results using fetched array (works!) 
    results = [results sortedArrayUsingDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]]; 

    // This works too but not needed anymore 
    /*results = [results sortedArrayUsingComparator:^(id obj1, id obj2) { 
     Tweet* tweet1 = (Tweet*)obj1; 
     Tweet* tweet2 = (Tweet*)obj2; 
     //return [tweet1.time compare:tweet2.time]; // ascending 
     return [tweet2.time compare:tweet1.time]; // descending 
    }];*/ 

    if ([results count] > 0) { 
     for (uint i = 0; i < [results count]; i++) { 
      Tweet* tweet = [results objectAtIndex:i]; 
      NSDate* date = Tweet.time; 
      NSLog(@"tweet date: %@", date); 
     } 
    } 
}]; 

Может кто-нибудь сказать мне, почему NSSortDescriptor не работает для моих извлечений?

Спасибо!

- Обновление -

Кажется, NSSortDescriptor отлично работает, когда я извлечь из основного (материнского) managedObjectContext на главном потоке без использования метода performBlock. Это по-прежнему не помогает мне сортировать выборки в управляемом объекте NSPrivateQueueConcurrencyType. Создание NSFetchRequest, NSSortDescriptor и NSPredicate внутри исполняемого блока также не устраняет проблему.

ответ

-1

При использовании по умолчанию для сравнения: селектор, можно упростить дескриптор:

NSSortDescriptor* timeDescriptor = [NSSortDescriptor 
             sortDescriptorWithKey:@"time" 
             ascending:NO]; 

Но это в сторону. Я думаю, что ключевым является тот факт, что вы обновляетесь из вложенного детского контекста. Подтвердите, что ваши объекты имеют постоянные идентификаторы объектов; они, возможно, не получили их еще, и, таким образом, это может быть проблемой с вашей добычей. Если это так, попробуйте вызвать objectPermanentIDsForObjects: до сохранения вложенного дочернего контекста.

4

Я тоже попал в проблему. Я выяснил, что если данные не будут сохранены вплоть до Persistent Store, сортировка не будет работать, если данные в главном контексте загрязнены, то есть изменены.

Например, если контексты чистые, без ожидающих изменений, сортировка работает. Если я изменяю только один атрибут объекта в родительском контексте, сортировка в дочернем контексте частной очереди не работает. Это очень неудачно. Я также сортирую метод массива, но это не так быстро, как сортировка в NSFetchRequest, тем более что мои данные уже проиндексированы этим ключом. Было бы намного быстрее отсортировать его в запросе выборки.

Я предполагаю, что, поскольку в контексте существуют несохраненные изменения, и NSFetchRequest переходит к самой базе SQLite, где изменения еще не существуют (контекст не сохраняется), он вообще не может сортировать на уровне базы данных.

Но в целом, это очень запутанно и пахнет как ошибка.

3

У меня была точно такая же проблема. Я решил проблему, установив свойство includesPendingChanges в экземпляре NSFetchRequest равным NO.