Обратное отношение не установлено (в обработчике KVO)

У меня очень странная проблема с обратными отношениями в Core Data, и мне удалось свести мою проблему к минимальному примеру, начиная с нового проекта в xcode на основе шаблона окна с поддержкой для Core Data (то есть там очень мало).

Предположим, у нас есть модель Core Data с тремя сущностями: Department, Employee и DepartmentSummary (своего рода сущность, представляющая некоторую статистику об отделе). Для простоты у нас есть только однозначные отношения:

DepartmentSummary   Department        Employee
---------------------------------------------------------
                    employee  <---->  department
department  <---->  summary

Это все, что есть в модели. В приложении : didFinishLaunchingWithOptions: мы создаем сотрудника и отдел и настраиваем KVO:

NSManagedObject* employee = 
 [NSEntityDescription 
   insertNewObjectForEntityForName:@"Employee"
   inManagedObjectContext:[self managedObjectContext]];
[employee addObserver:self forKeyPath:@"department" options:0 context:nil];

NSManagedObject* department = 
  [NSEntityDescription 
    insertNewObjectForEntityForName:@"Department"
    inManagedObjectContext:[self managedObjectContext]];
[department setValue:employee forKey:@"employee"];

Назначение обработчика KVO - создать сводку для отдела, как только отдел сотрудника установлен:

- (void) observeValueForKeyPath:(NSString *)keyPath 
                       ofObject:(id)object 
                         change:(NSDictionary *)change 
                        context:(void *)context 
{
     [self createSummary:object];
}

createSummary прост: он создает новый объект сводки и связывает его с отделом, а затем проверяет, что также установлено обратное отношение от отдела к объекту сводки :

- (void) createSummary:(NSManagedObject*)employee 
{
    NSManagedObject* department = [employee valueForKey:@"department"];
    NSManagedObject* summary = 
     [NSEntityDescription 
       insertNewObjectForEntityForName:@"DepartmentSummary"
       inManagedObjectContext:[self managedObjectContext]];

    [summary setValue:department forKey:@"department"];

    NSAssert([department valueForKey:@"summary"] == summary, 
             @"Inverse relation not set");
}

Это утверждение не выполняется. Действительно, если мы печатаем объекты отдела и сводки после того, как отдел сводки был установлен, мы получим

entity: DepartmentSummary; 
    id: ..DepartmentSummary/..AA14> ; 
  data: { 
    department = "..Department/..AA13>";
  }

для сводки, как и ожидалось, но

entity: Department; 
    id: ..Department/..AA13> ; 
  data: {
    employee = "..Employee/..AA12>";
    summary = nil;
  }

для отдела (с сводкой nil ). Однако если мы отложим вызов createSummary , чтобы он не запустился до следующей итерации цикла выполнения:

- (void) observeValueForKeyPath:(NSString *)keyPath 
                       ofObject:(id)object 
                         change:(NSDictionary *)change 
                        context:(void *)context 
{
     [self performSelector:@selector(createSummary:) 
                withObject:object 
                afterDelay:0];
}

, тогда все будет работать, как ожидалось.

Задержка утверждения вместо этого не помогает: обратное отношение действительно не устанавливается в графе объектов , хотя оно и устанавливается в базе данных (если бы вы сохранили базу данных и перезапустили приложение, теперь внезапно появится обратная зависимость.)

Это ошибка в Core Data? Это задокументированное поведение, которое я пропустил? Я использую Core Data не предназначенным для этого способом?

Обратите внимание, что обработчик KVO вызывается , в то время как Core Data (автоматически) устанавливает (другое) обратное : мы вручную устанавливаем поле сотрудника отдела, Core Data автоматически устанавливает значение сотрудника отдел , которое, в свою очередь, запускает обработчик KVO. Возможно, это слишком много для Core Data :) Действительно, когда мы устанавливаем

[employee setValue:department forKey:@"department"];

, все снова работает, как ожидалось.

Любые указатели будут оценены.

9
задан edsko 20 August 2011 в 09:00
поделиться