3

У меня есть NSFetchedResultsController, который извлекает данные из хранилища CoreData. Когда инициализируется frc, я вызываю performFetch и проверяет количество выбранных объектов в frc.fetchedObjects, результат равен 0, как и должно быть.NSFetchedResultsController, вызванный обновлением объекта NSManagedObject. Зачем?

В другом месте в коде я называю:

[obj.managedObjectContext refreshObject:obj mergeChanges:NO] 

Хотя я даже не уверен, что нужно это имеет побочный эффект вызывает КОП принести некоторые объекты, которые не были изначально и, получаемые не должен В любом случае, если вы хотите использовать запрос, его можно получить. Эти объекты являются точно такими же объектами, с которыми вызывался refreshObject:mergeChanges:.

Почему это происходит?

Edit:

Это не происходит для этого запроса:

query.predicate = [NSPredicate predicateWithFormat:@"(cartEntry != NULL) AND (urlWeb = NULL)", version, dateUrlExpire]; 

frc = [[NSFetchedResultsController alloc] initWithFetchRequest:query managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 
frc.delegate = self; 
[frc performFetch:&error]; 

Но когда я изменить запрос к этой версии, то это происходит (urlWebVersion и urlWebDate являются NULL для всех записей):

query.predicate = [NSPredicate predicateWithFormat:@"(cartEntry != NULL) AND ((urlWeb = NULL) OR (urlWebVersion != %@) OR (urlWebDate > %@))", version, dateUrlExpire]; 

* Edit # 2 *

Вот минимальный пример кода, который показывает странное поведение (отсутствие ошибок во время выполнения):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 

    NSError *error; 

    // Create an empty entity with the optional fields attr1 (string) and attr2 (date) 
    Entity *e = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:[self managedObjectContext]]; 

    // Save entity 
    [_managedObjectContext save:&error]; 

    // Setup fetched results controller 
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"(attr1 != %@) AND (attr2 != %@)", @"", [NSDate new], nil]; 

    NSFetchRequest *query = [[NSFetchRequest alloc] initWithEntityName:@"Entity"]; 
    query.predicate = pred; 
    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"attr1" ascending:NO]]; 

    frc = [[NSFetchedResultsController alloc] initWithFetchRequest:query managedObjectContext:_managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 

    frc.delegate = self; 

    // Load data 
    [frc performFetch:&error]; 

    // Output #1 
    NSLog(@"%ld", frc.fetchedObjects.count); 

    [_managedObjectContext refreshObject:e mergeChanges:NO];   

    return YES; 
} 

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{ 
    NSLog(@"%ld", controller.fetchedObjects.count); 
} 

Выход:

2015-01-22 22:53:44.293 CoreDataBug[10740:1445186] 0 
2015-01-22 22:53:44.317 CoreDataBug[10740:1445186] 1 
+0

Не могли бы вы включить извлечение, которое выполняется? Имеет ли NSFRC (NSFetchedResultsController) набор делегатов? Если задан делегат (и, по крайней мере, один метод реализован), NSFRC автоматически выполнит выборку, когда появятся новые данные. «Если вы не укажете делегата, контроллер не отслеживает изменения в управляемых объектах, связанных с его контекстом управляемого объекта». https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsController_Class/ –

+1

'(urlWebVersion! =% @)' похоже на вероятного виновника. Если 'urlWebVersion' является' NULL', то он, безусловно, не будет равен 'version1', что делает утверждение истинным и, следовательно, возвращает запись. –

+0

О, ты, наверное, прав. Но почему размер начального результата равен 0? Сразу после 'performFetch' – Xyand

ответ

2

Ваша проблема заключается в том, что У NSPredicate есть трудности с сопоставлением != с нулевым значением. Например, в вашей Редактировании 2 ваша линия:

[NSPredicate predicateWithFormat:@"(attr1 != %@) AND (attr2 != %@)", 
@"", [NSDate new], nil]; 

, как вы знаете, возвращает нуль после запроса на выборку. (Там есть лишний ноль, но это ничего не влияет). Но смена его на:

NSPredicate *pred = [NSPredicate predicateWithFormat: 
@"((attr1 != %@) || (attr1 == nil)) AND ((attr2 != %@) || (attr2 == nil))", 
@"", [NSDate new]]; 

возвращает объекты, хотя логически они одинаковы.

Это задокументированное поведение, хотя и трудно следовать за чем-то настолько противоречащим интуиции, см. Подраздел «Использование нулевых значений» в Predicate Programming Guide.

Непонятно, почему обновление объекта приведет к внезапному совпадению предиката; это может быть ошибкой. Однако, учитывая приведенную выше документацию, != не следует использовать для значений, которые могут быть равны нулю (если не проверка != nil) без сопряжения || (x = nil). Больше, чем немного раздражает и противостоят интуитивно понятным.

Смежные вопросы