2009-07-02 3 views
8

Я пишу свое первое приложение для iPhone/Cocoa. Он имеет два вида таблицы внутри навигационного представления. Когда вы касаетесь строки в первом представлении таблицы, вы попадаете во второй вид таблицы. Я хотел бы, чтобы второе представление отображало записи из объектов CoreData, связанных со строкой, к которой вы коснулись первого представления.Передача ManagedObjectContext ко второму представлению

У меня есть данные CoreData, которые отображаются в первом представлении таблицы. Вы можете коснуться строки и перейти ко второму представлению таблицы. Я могу передавать информацию из выбранного объекта с первого на второй. Но я не могу получить второе представление, чтобы сделать свой выбор CoreData. Для жизни я не могу получить объект managedObjectContext для перехода ко второму контроллеру представления. Я не хочу выполнять поиск в первом представлении и передавать словарь, потому что я хочу иметь возможность использовать поле поиска для уточнения результатов во втором представлении, а также вставить новые записи в данные CoreData.

Вот функция, которая переходит от первого ко второму виду.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    // Navigation logic may go here -- for example, create and push another view controller. 
    NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath]; 
    SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil]; 

    secondViewController.tName = [[selectedObject valueForKey:@"name"] description]; 
    secondViewController.managedObjectContext = [self managedObjectContext]; 

    [self.navigationController pushViewController:secondViewController animated:YES]; 
    [secondViewController release]; 
} 

И это функция внутри SecondViewController, что выходит из строя:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.title = tName; 

    NSError *error; 
    if (![[self fetchedResultsController] performFetch:&error]) { // <-- crashes here 
     // Handle the error... 
    } 
} 

- (NSFetchedResultsController *)fetchedResultsController { 

    if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    /* 
    Set up the fetched results controller.  
    */ 
    // Create the fetch request for the entity. 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    // Edit the entity name as appropriate. 
     // **** crashes on the next line because managedObjectContext == 0x0 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    // <snip> ... more code here from Apple template, never gets executed because of the crashing 

    return fetchedResultsController; 
} 

Любые идеи о том, что я делаю неправильно здесь?

managedObjectContext - это неживой объект.

ОБНОВЛЕНИЕ: я вставил NSLog (описание [[managedObjectContext registeredObjects]]); в viewDidLoad и, похоже, managedObjectContext передается просто отлично. Тем не менее, все еще рушится.

Нагрузочного приложение из-за неперехваченное исключение «NSInternalInconsistencyException», причина: «+ entityForName: не мог определить местонахождение NSManagedObjectModel для имени объекта„SecondEntity“»

+0

Что происходит, когда вы помещаете код, который инициализирует выбранный контроллер результатов в viewDidLoad? У меня есть приложение, которое делает по сути одно и то же, и оно отлично работает для меня, но я создаю свой обработчик получаемых результатов непосредственно в viewDidLoad с помощью initWithFetchRequest: managedObjectContext: sectionNameKeyPath: cacheName :. – Tim

+0

@Tim Я просто попробовал это, он падает таким же образом. Странно, что если я установил точку останова, все переменные-члены self будут NULL, но заголовок будет правильно установлен, так что это не может быть правдой. – amo

ответ

7

О, это интересно. Я провел некоторое время с трассировкой стека, и я думаю, что я понял.

Так что pushViewController вызывает viewDidLoad не один раз, а дважды.При первом вызове viewDidLoad объекты, похоже, не создаются должным образом. Во второй раз. Таким образом, при первом запуске этого кода он не может получить доступ к managedObjectContext и генерирует исключение. Во второй раз, когда все работает, все в порядке. Без падений.

Существует много ссылок на проблемы с viewDidLoad, выполняемые несколько раз в Google, поэтому я думаю, что решение состоит в том, чтобы не выполнять эту инициализацию запроса на выборку в viewDidLoad.

+0

Как насчет viewDidAppear? – film42

0

Вы уверены, что есть объект, называемый «SecondEntity»? (Это был бы простой способ интерпретировать сообщение об ошибке.)

Однако, если это взаимодействие с основным списком -> подробное представление, я бы предложил передать выделенный объект непосредственно во второй контроллер представления, а не давать это просто «tname». Этот объект предположительно содержит все необходимое для заполнения второй таблицы непосредственно через свои свойства.

Таким образом, вы фактически не делаете явной выборки во втором контроллере представления. То есть:

@interface SecondViewController : UITableViewController 
@property (nonatomic, retain) NSManagedObject *selectedObject; 
@end 

@implementation SecondViewController 
- (void)viewDidLoad 
{ 
    NSMutableArray *stuff = [[[selectedObject valueForKey:@"aToManyRelationship"] allObjects] mutableCopy]; 
    // sort stuff the way you want to display them, etc. 
} 
... 
+0

Да, сущность существует. Это не главный список-> подробнее .. это больше похоже на категории-> элементы, и я хочу иметь возможность напрямую взаимодействовать с хранилищем данных, потому что второе представление действительно является основным экраном взаимодействия, поэтому я не хочу чтобы просто передать снимок ко второму виду. – amo

0

Просто для Пинки .. попробуйте заменить:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 

с:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:[self managedObjectContext]]; 

Вы устанавливаете managedObjectContext через сеттер, а затем пытается получить доступ к Ивар непосредственно. В зависимости от того, как определяются ваши свойства, это может быть неверно. [self managedObjectContext] попытается получить доступ к значению через getter, а не напрямую.

+0

Интересно. Я попробую это, когда вернусь домой. – amo

+0

Значит ли это, что self.title = tName также плохая форма? – amo

+1

Совсем нет. Хотя я не уверен, откуда происходит tName. Точечный синтаксис в Objective C * - это * вызов ваших методов доступа, даже если он может * отображаться *, чтобы бить ivars. – mmc

1

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

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

Если ваше приложение настроено как приложение демо CoreDataBooks от iphone Dev центр с основным UIApplicationDelegate также управлять стеком CoreData, то вы должны быть в состоянии сделать следующее:

if (managedObjectContext == nil) { managedObjectContext = [[[UIApplication sharedApplication] delegate] managedObjectContext]; }

Это должно Покажи фокус.

-2

Одна вещь наверняка, строка: secondViewController.managedObjectContext = [self managedObjectContext];

Должно быть: secondViewController.managedObjectContext = self.managedObjectContext;

Если текущий объект не реализует метод под названием «managedObjectContext», который возвращает эту переменную.

-1

Возможно, это проблема.

короткий ответ: удалите приложение и запустите его снова.

длинный ответ:

Если построить и запустить свой проект, CoreData сохранит вашу модель туда, где вы сказали (постоянного местоположения магазина).

Если вы изменили что-то в модели CoreData, при повторном запуске приложения новая модель не будет соответствовать сохраненной модели, дающей вам эту ошибку.

Чтобы устранить это, удалите приложение. Это избавит вас от сохраненной модели, и когда вы запустите ее снова, она воссоздает вашу новую модель.

18

Вы можете подавить «-managedObjectContext» не найден в предупреждении протоколов путем первой отливки вашего делегата приложения:

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; } 
0

Я имел эту проблему и обнаружили, что INIT сообщение моего объекта был доступ к managedObjectContext до setManagedObjectContext было называют ...

До:

dataController = [[DataController alloc] init]; 
[dataController setManagedObjectContext:[self managedObjectContext]]; 

После:

dataController = [DataController alloc]; 
[dataController setManagedObjectContext:[self managedObjectContext]];    
[dataController init]; 

feh. Ошибка новичков.

0

Apple предоставляет образец проекта под названием «iPhoneCoreDataRecipes». Существует очень интересная статья о прохождении NSManagedObjectContext here Если вы пытаетесь реализовать такую ​​логику, что каждый managedObjectContext является как остров на своем собственном в каждом UIViewController

Попробуйте изменить код

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; } 

С этой

if (managedObjectContext == nil) { managedObjectContext = self.managedObjectContext } 
1

в своем первом tableViewController, вы можете пройти managedObjectContext по: secondTableController.managedObjectContext = [(AppDelegate *) [[UIApplication sharedApplication ] delegate ] managedObjectContext ], может быть, это нормально

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