Как передать NSManagedObjectContext через XIB интерфейсного конструктора

У меня есть простое приложение iOS с одним UIViewController под UINavigationController. UIViewController имеет IBOutlet для NSManagedObjectContext.

AppDelegate имеет IBOutlet для навигационного контроллера, но не для контроллера представления. Контроллер представления автоматически создается как процесс XIB (как дочерний элемент навигационного контроллера).

Как с помощью этой настройки можно четко назначить или передать NSManagedObjectContext делегата приложения в свойство IBOutlet контроллера представления. На пути есть навигационный контроллер :), и у делегата приложения нет прямого свойства для UIViewController.

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


person Luther Baker    schedule 03.03.2011    source источник
comment
Я думаю, что также стоит рассмотреть приложение, которое имеет 9 контроллеров представления, используемых в разное время, и всем им нужен доступ к управляемому контексту. В некоторых случаях представления-A и представления-C нуждаются в контексте, а представление-B — нет. Наивный подход, который просто передает его каждому контроллеру представления по мере их создания, кажется беспорядочным. Означает ли это, что представление-A создает представление-B с контекстом (хотя представление-B в нем не нуждается), чтобы представление-B могло создать представление-C и передать его? Я считаю, что это делает мои тупые контроллеры представления слишком умными, а приложение негибким.   -  person Luther Baker    schedule 03.03.2011


Ответы (3)


Вам не нужно передавать его, просто возьмите его из делегата приложения по мере необходимости:

#import "MyAppDleegate.h"

NSManagedObjectContext* moc = [(MyAppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext];
person Adam Eberbach    schedule 03.03.2011
comment
Это один подход (и действительно очень практичный), но в определенной степени он жестко кодирует контекст в самих представлениях. Мне нравится, что он инвертирует настройку, но как синглтон нарушает принцип внедрения зависимостей. Например, было бы сложно провести модульное тестирование этого конкретного контроллера представления изолированно, поскольку он будет продолжать обращаться к UIApplication и AppDelegate за необходимыми ему ресурсами. Идеальным решением было бы предоставление контекста контроллеру представления во время выполнения, хитрость заключается в том, чтобы подключить его аля IB. - person Luther Baker; 03.03.2011
comment
Правда — в некоторых приложениях, где есть несколько потоков, обращающихся к управляемым объектам, я использовал категорию в NSManagedObjectContext, которая создает moc по мере необходимости, используя имя потока в качестве идентификатора — затем они сохраняются в словаре с именем потока в качестве ключа. Очевидно, вы должны назвать все потоки и утверждать, если вы получаете запрос от безымянного потока. Это последнее, что беспокоит меня в использовании IB, мне нравится, как XCode 4 теперь устанавливает соединения, но необходимость открывать уловки для выполнения таких вещей, как передача moc, приводит в бешенство. - person Adam Eberbach; 04.03.2011

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

Вот как выглядит application:didFinishLaunchingWithOptions: в одном из моих проектов Core Data.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    LocationsViewController *lvc = (LocationsViewController *)self.navigationController.topViewController;
    lvc.managedObjectContext = self.managedObjectContext;
    assert(lvc.managedObjectContext != nil);
    [self.window addSubview:self.navigationController.view];
    [self.window makeKeyAndVisible];

    return YES;
}

Вы увидите, что я также начинаю с UINavigationController с одним корневым контроллером представления.

person Mark Adams    schedule 03.03.2011
comment
Спасибо, Марк. К сожалению, у меня нет ссылки на контроллер основного представления в моем делегате приложения — только контроллер навигации. - person Luther Baker; 03.03.2011
comment
Но вы настроили свой главный контроллер представления в Интерфейсном Разработчике как корневой контроллер представления вашего навигационного контроллера. Просто попросите навигационный контроллер вернуть контроллер вида сверху. Настройте общедоступное свойство на контроллере представления для NSManagedObjectContext. Используйте self.managedObjectContext из AppDelegate, чтобы установить свойство managedObjectContext в контроллере представления. - person Mark Adams; 03.03.2011
comment
Да, я мог бы это сделать, но искал способ сделать это в XIB Interface Builder. У меня есть 9 других контроллеров представлений, которых нет в стеке навигации, которым также нужен контекст управляемого объекта, и я хотел бы применить его и к ним. - person Luther Baker; 04.03.2011
comment
К сожалению, мне тоже не удалось подключить это в IB. Я просто знаю, что должна быть причина, по которой Apple рекомендует передавать ссылки. - person Mark Adams; 04.03.2011

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

Добавьте выход к вашему делегату приложения для вашего корневого контроллера представления и подключите его. Затем делегат приложения может передать контроллеру ссылку на контекст управляемого объекта.

Что касается вашего вопроса о нескольких контроллерах представления, мне интересно, какое реальное приложение может иметь контроллер представления (A), которому нужны данные, загружать другой контроллер представления (B), которому не нужны данные, а затем третий (с) что опять нужны данные? Реальный пример может помочь, если он у вас есть.

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

person Caleb    schedule 05.03.2011