Привязки с NSManagedObject из дочернего контекста работают только для новых объектов - PullRequest
0 голосов
/ 23 августа 2011

Справочная информация:

В моем приложении я специально нацелился на Mac OS X Lion. Эта проблема связана с базовыми данными, NSPopover и дочерним NSManagedObjectContext (созданным с использованием нового свойства parentContext NSManagedObjectContext).

У меня есть таблица NSManagedObjects класса "Местоположение". Есть кнопка Add, которая вызывает addLocation: и если дважды щелкнуть строку таблицы, я вызываю tableViewDoubleClick:.

В любом случае я создаю новый NSManagedObjectContext и устанавливаю его родительский контекст в контекст документа. Затем я либо создаю новое местоположение в этом контексте, либо выбираю местоположение, которое нужно отредактировать, из временного контекста. Я установил для свойства popOverppedObject указанное местоположение. Если я отменю поповер, ничего не сохранится. Если пользователь нажимает кнопку «Сохранить» во всплывающем окне, я просто вызываю сохранить: во временном контексте, и изменения переносятся в основной контекст.

addLocation:

- (IBAction)addLocation:(id)sender
{    
    LocationEditViewController *popupController = [[[LocationEditViewController alloc] init] autorelease];
    popupController.title = @"Add New Location";

    NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
    tempContext.parentContext = self.document.managedObjectContext;

    Location *tempLocation = [NSEntityDescription insertNewObjectForEntityForName:@"Location" inManagedObjectContext:tempContext];

    popupController.representedObject = tempLocation;
    popupController.managedObjectContext = tempContext;

    [popupController.popover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
}

tableViewDoubleClick:

- (void)tableViewDoubleClick:(id)sender
{
    NSInteger selectedRow = [self.table selectedRow];
    if (selectedRow != -1) 
    {
        NSRect rectOfSelectedRow = [self.table rectOfRow:selectedRow];
        LocationEditViewController *popupController = [[[LocationEditViewController alloc] init] autorelease];
        popupController.title = @"Edit Location";

        Location *locationToEdit = [self.locationController.selectedObjects objectAtIndex:0];

        NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
        tempContext.parentContext = self.document.managedObjectContext;

        Location *tempLocation = (Location *)[tempContext fetchObjectEqualTo:locationToEdit]; // Custom fetch helper method        

        popupController.managedObjectContext = tempContext;
        popupController.representedObject = tempLocation;

        [popupController.popover showRelativeToRect:rectOfSelectedRow ofView:sender preferredEdge:NSMaxXEdge];

    }
}

Вот проблема, которую я хотел бы объяснить:

Текстовые поля в всплывающем окне связаны с представленным объектом всплывающего окна через привязки в кончике. Они прекрасно работают с новым объектом (addLocation :).

Если Location является существующим объектом (tableViewDoubleClick :), привязки работают достаточно хорошо, чтобы предварительно заполнить поля свойствами Location. Однако изменение текста в полях вообще не изменяет свойства местоположения. Когда во всплывающем окне была нажата кнопка «Сохранить», я попытался зарегистрировать свойства местоположения перед сохранением временного контекста. Если это существующий объект, все, что я ввожу в поля, не отражается в свойствах Location - как будто привязки взаимодействуют только в одном направлении.

Мой обходной путь: Я обнаружил, что если я пропущу привязки и просто вручную установлю в свойствах Location значения в текстовых полях перед сохранением, изменения вступят в силу.

- (IBAction)popoverSave:(id)sender
{
    // These two methods always work. But if I remove these and use bindings instead, it only works for NEW Locations.
    [(Location *)self.representedObject setLabel:self.labelField.stringValue];
    [(Location *)self.representedObject setLocation:self.locationField.stringValue];

    NSLog(@"representedObject = %@", self.representedObject);

    NSError *error = nil;
    [self.managedObjectContext save:&error];
    [self.popover close];
}

Мне бы очень хотелось знать , почему это так, на тот случай, если я действительно что-то делаю не так.

Спасибо!

1 Ответ

1 голос
/ 24 августа 2011

Я думаю, вполне вероятно, что это приведение в следующих строках:

[(Location *)self.representedObject setLabel:self.labelField.stringValue];
[(Location *)self.representedObject setLocation:self.locationField.stringValue];

... это заставляет их работать. Если это так, то, вероятно, у вас есть NSObject или NSManagedObject, установленный где-то в привязках как класс вместо Location класса. Когда привязка отправляет сообщение, специфичное для класса Location, например, установите атрибут с определенным именем для универсального класса, универсальный класс молча игнорирует сообщение.

Кстати, я бы предостерег от использования нескольких контекстов вместо использования API отмены. Я вижу, что многие люди попадают в неприятности таким образом. Откатить один контекст проще, чем управлять несколькими.

...