Передача ManagedObjectContext для просмотра контроллеров с использованием раскадровок с корневым UITabBarController - PullRequest
6 голосов
/ 28 февраля 2012

Используя раскадровки, вы не имеете легкого доступа к первому контроллеру представления в appDelegate (хотя, как только вы это сделаете, prepareForSegue упрощает передачу ManagedObjectContext вниз по стеку навигации.

Я решил предоставить каждому контроллеру представления (или суперклассу каждого контроллера представления), требующему, чтобы Core Data, доступ к члену moc:

@synthesize moc = _moc;
@property (nonatomic) __weak NSManagedObjectContext *moc;

Меня это беспокоит, потому что это не выглядит очень элегантным способом - слишком много кода. Но прямое назначение требует указания абсолютных индексов в массивах viewControllers и изменения appDelegate каждый раз, когда изменяется требование для ManagedObjectContexts

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;

    // rootView gets a tab bar controller
    for(UINavigationController *navController in tabBarController.viewControllers) {

        for(UIViewController *viewController in navController.viewControllers) {

            if([viewController respondsToSelector:@selector(setMoc:)]) {
                [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext];
                NSLog(@"Passed moc to %@", [viewController description]); 
            }
        }
    }

    return YES;
}

Каковы подводные камни этого подхода и есть ли лучший способ? Лучше попробовать и быть более общим:

- (void)assignManagedObjectContextIfResponds:(UIViewController *)viewController {

    if([viewController respondsToSelector:@selector(setMoc:)]) {
        [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext];
        NSLog(@"Passed moc to %@", [viewController description]); 
    }

}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSMutableArray *viewControllers = [NSMutableArray array];

    UIViewController *firstLevelViewController = self.window.rootViewController;

    if([firstLevelViewController respondsToSelector:@selector(viewControllers)]) {

        NSArray *firstLevelViewControllers = [firstLevelViewController performSelector:@selector(viewControllers)];

        for(UIViewController *secondLevelViewController in firstLevelViewControllers) {

            if([secondLevelViewController respondsToSelector:@selector(viewControllers)]) {

                NSArray *secondLevelViewControllers = [secondLevelViewController performSelector:@selector(viewControllers)];

                for(UIViewController *thirdLevelViewController in secondLevelViewControllers) {

                    [viewControllers addObject:thirdLevelViewController];
                }

            } else {
                [viewControllers addObject:secondLevelViewController];
            }
        }
    } else {
        // this is the simple case, just one view controller as root
        [viewControllers addObject:firstLevelViewController];
    }

    // iterate over all the collected top-level view controllers and assign moc to them if they respond
    for(UIViewController *viewController in viewControllers) {
        [self assignManagedObjectContextIfResponds:viewController];
    }

    return YES;
}

Ответы [ 2 ]

4 голосов
/ 29 февраля 2012

Не знаю, правильно ли я понял, но почему бы вам не оставить контекст управляемого объекта непосредственно в классе AppDelegate и оставить там всю логику для создания экземпляра. И с тех пор вы можете попросить об этом.

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

тогда вы можете вспомнить его в любое время из любого места.

NSManagedObjectContext *moc = [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];

Для удобства я объявил определение для него:

#define MOC [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]

Поэтому это становится:

[MOC save:&error];

Вы можете взять это где угодно. Просто попробуйте взглянуть на автоматически сгенерированный код для приложения CoreData в XCode, вы увидите, что многие средства доступа с CoreData находятся там, а само CoreData лениво инициализируется при первом запросе.

2 голосов
/ 05 марта 2012

Адам,

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

Там нет ничего существенно отличающегося, так что я буду двигаться дальше.

Я думаю, что смысл в том, что раскадровки, IMO, наполовину испечены.Исходя из .Net фона, чего явно не хватает, это каркас построителя объектов в сочетании с контейнером IoC.Когда Apple добавит, что раскадровки будут потрясающими.Когда каркас раскадровки сможет взглянуть на destinationViewController, определить его зависимости и разрешить их из жизни контейнера, будет здорово.На данный момент все, что он действительно может сделать, это взглянуть на destinationViewController и инициировать вам универсальный, который имеет ограниченное использование.

К сожалению, потому что это недоделанное решение, я придерживаюсь традиционного подхода длятеперь, чтобы все мои контроллеры представления были выделены и init'd вручную, и что еще более важно, я добавил метод для каждого контроллера представления в initWithMOC: (MOC *) moc;

Архитектор во мне говорит мнеэтот код более надежен, я полагаю, это вопрос мнения о том, стоит ли компромисс.

Кто-нибудь еще придумал лучший способ?

CA.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...