2011-07-31 2 views
0

Я борюсь с каким-то странным поведением в Core Data. У меня довольно стандартная настройка, используя пример CoreDataBook: у меня есть RootView, который использует NSFetchedResultsController для отображения списка элементов. Элемент имеет несколько атрибутов и отношений с другими объектами. У меня есть DetailView, который я использую, чтобы создать новый Item, а также отредактировать существующий элемент, который я представляю модально. В DetailView: viewDidLoad, я создаю новый managedObjectContext, в котором я хочу сделать все изменения ... если пользователь нажимает Save, я сохраняю этот контекст и объединяя изменения; в противном случае, если пользователь нажимает на отмену, все эти изменения просто исчезают.Основные данные - отношения идут ноль неожиданно

«Добавить новый элемент» часть этого прекрасно работает, но когда я выбираю строку, чтобы вывести тот же DetailView, что и существующий элемент, одно из отношений (которое отлично видно в RootView в отладчике) внезапно становится nil, когда он представлен в DetailView. Вот код для отображения DetailView в didSelectRowAtIndexPath UITableView в:

Item *managedObject = (Item *)[self.fetchedResultsController objectAtIndexPath:indexPath]; 
    DetailView *childController = [[DetailView alloc] initWithNibName:@"DetailView" bundle:nil]; 

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:childController];  

    childController.existingItem = managedObject; 

    // ** Item's relationship to Title is not nil at this point 
    [self presentModalViewController:navController animated:YES]; 
    // ** Item's relationship Title is now nil 

    [childController release]; 
    [navController release]; 

Там нет ничего лишнего неординарного в контроллере DetailView, что бы привести к этому. На самом деле, у него даже нет шансов нанести какой-либо ущерб ... как только он начнется, существующее отношение Item.title уже равно нулю. [existingItem является сохраненным свойством DetailView]

Любая идея, где я должен начать изучать это? За последние несколько часов меня сводило с ума. Вот код в DetailView viewDidLoad, но отношения ноль еще до того, как это называется:

// Create a new managed object context 
    NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init]; 
    self.addEditContext = addingContext; 
    [addingContext release]; 
    [self.addEditContext setPersistentStoreCoordinator:[[appDelegate managedObjectContext] persistentStoreCoordinator]]; 

    if (!self.existingItem) { 
     self.existingItem = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext: self.addEditContext]; 

    }else{ 
     self.existingItem = (Item *)[self.addEditContext objectWithID:[self.existingItem objectID]]; 
    } 

Названное зависимость устанавливается путем выбора из некоторого списка:

self.existingItem.title = selectedTitle; 

В экономии: метод, за исключением I addEditContext и объединить изменения с AppDelegate контекста:

NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; 
    [dnc addObserver:self selector:@selector(addControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object: self.addEditContext]; 

    // Save the context. 
    NSError *error = nil; 
    if (![self.addEditContext save:&error]){ 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    } 

    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.addEditContext]; 
    self.addEditContext = nil; 

В addControllerContextDidSave:

- (void)addControllerContextDidSave:(NSNotification*)saveNotification { 
    id appDelegate = [[UIApplication sharedApplication] delegate]; 
    // Merging changes causes the fetched results controller to update its results 
    [[appDelegate managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification]; 
} 

Таким образом, файл save: stuff отлично подходит для нового элемента, но когда этот элемент установлен на существующий и снова загружен, self.existingItem.title равен нулю. И это ничто из того, что оно представлено в контроллере представления (хотя это не ноль, прежде чем он будет представлен). Таким образом, в основном контексте он отлично загружает отношения с Item и it title, но затем название внезапно исчезает, когда оно представлено в presentModalViewController: navController.

Действительно странно. Если кто-то может пролить свет на это, это будет действительно оценено.

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

ответ

1

Ваш дизайн все излишне сложный и избыточный. Я думаю, что отношения показывают как ниль, потому что у вас есть неправильный класс, назначенный вашему свойству self.existingItem.

Во-первых, нет причин создавать другой контекст только для другого представления на той же самой теме. Просто передайте существующий контекст следующему виду и сохраните головную боль, связанную с объединением, в контекст без каких-либо функциональных причин.

Во-вторых, этот блок:

}else{ 
    self.existingItem = (Item *)[self.addEditContext objectWithID:[self.existingItem objectID]]; 
} 

... совершенно бессмысленно, потому что вы настраиваете self.existingItem к себе. Вы, возможно, также написано:

self.existingItem = self.existingItem; 

... потому что идентификаторы объектов фиксируются в постоянном хранилище один раз объект, как был спасен. Если объект не был сохранен, идентификатор является временным, а другой контекст не сможет его найти.

Наиболее вероятной причиной проблемы является определение свойства existingItem. Если вы определили его как id или NSManagedObject, он не ответит на селектор title и вернет нуль. Это было бы ошибкой, но вы использовали его как Item, поэтому компилятор считает, что он ответит на все сообщения, которые будет иметь объект Item.

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

+0

Спасибо за ваши комментарии. existingItem определенно задан как @property (сохранить, неатомный) Item * existingItem, так что это не так. Причина, по которой я создал другой контекст, заключается в том, что я хочу, чтобы пользователь сделал кучу изменений в existingItem (или при добавлении нового), но есть кнопка отмены на странице, чтобы откатить все в случае, если пользователь решит. Я чувствовал, что самый простой способ сделать это - создать отдельный контекст, чтобы изменения не влияли на контекст основного потока. Есть лучший способ сделать это? –

+0

Я также попытался использовать NSUndoManager для отслеживания и отката изменений вместо нескольких контекстов. Но у него тоже есть та же проблема. Взаимодействие «title» отлично в файле didSelectRowAtIndexPath RootView до момента, когда он вызывает [self presentModalViewController: navController animated: YES], а затем он просто исчезает как из RootView, так и из DetailView. Теперь с UndoManager, когда изменения отменены, заголовок восстанавливается в представлении, но он все еще не отображается в DetailView (хотя все в одном контексте). Означает ли это, что я могу ошибаться? –

+0

Кроме того, я добавил еще одно соотношение (1 к 1), которое отлично работает и отображается в DetailView. Соотношение заголовков много-к-одному (от элементов к заголовку ... так что заголовок может быть связан с несколькими элементами, но каждый элемент имеет один заголовок). –

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