2008-10-28 3 views
7

Я как-то царапал себе голову этим неделю назад, и теперь, когда у меня появился немного больше опыта какао, я чувствую, что имею представление о том, что может происходить.Является ли parentViewController всегда навигационным контроллером?

Я делаю приложение, которое управляется UINavigationController. В AppDelegate я создаю экземпляр этого класса, используя «page 1» в качестве Root View Controller.

UINavigationController *aNavigationController = [[UINavigationController alloc] 
    initWithRootViewController:page1ViewController]; 

Теперь вот где у меня проблема. Из «страницы 1» я хотел бы использовать контроллер модального представления, который скользит по интерфейсу, а затем исчезает после того, как пользователь сделал редактирование. Я делаю это с помощью кода, как это, внутри Page1ViewController:

[self presentModalViewController:myModalViewController animated:YES]; 

Когда модальный View Controller нет, я хочу значение на «Страница 1» меняться в зависимости от того, что вводится пользователем в модальной View Controller. Итак, я написал код, как это, который находится в модальной View Controller:

[self.parentViewController dismissModalViewControllerAnimated:YES]; 
[self.parentViewController doSomethingPleaseWithSomeData:someData]; 

Обновление на странице 1, не происходит, и мне потребовалось много времени, чтобы понять, что сообщение «doSomethingPleaseWithSomeData» было не отправляется в Page1ViewController, а контроллер навигации.

Этого всегда следует ожидать при использовании навигационных контроллеров? Возможно, я настроил что-то неправильно? Есть ли простой способ получить доступ к контроллеру просмотра, который я хочу (в данном случае, Page1ViewController).

ответ

14

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

@property (nonatomic, assign) id <MyModalViewDelegate> delegate; 

и соответствующий протокол

@protocol MyModalViewDelegate 
@optional 
    - (void)myModalViewControllerDidFinish:(MyModalViewController *)aModalViewController; 
@end 

Когда пользователь заканчивает с вашей точки зрения (например, отводы кнопку сохранения), отправьте это сообщение:

if ([self.delegate respondsToSelector:@selector(myModalViewControllerDidFinish:)]) 
    [self.delegate myModalViewControllerDidFinish:self]; 

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

Так Apple решает эту проблему, например, в UIImagePickerController и UIPersonPickerController.

4

Есть несколько способов, которыми вы можете справиться. Проще всего, наверное, просто добавить свойство UIViewController в myModalViewController и установить его на page1Controller, прежде чем представить его:

myModalViewController.logicalParent = self; //page1Controller 
[self presentModalViewController:myModalViewController animated:YES]; 

Просто убедитесь, что вы добавляете соответствующий экземпляр переменной @property и @synthesize для logicalParent в myModalViewController, то у вас будет способ передачи данных обратно в ViewController, который инициировал модальное диалоговое окно. Это также для передачи данных вперед и назад между различными уровнями навигации, прежде чем вы нажимаете и выкладываете их в стек.

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

+0

Выполняет именно то, что я хочу, спасибо! Я новичок в Cocoa, но не MVC. Дело в том, что, будучи веб-разработчиком Java, я почти всегда забываю, что контроллеры в «С» МОГУТ взаимодействовать друг с другом! – bpapa

+0

Хороший ответ, но почему это так? Очевидно, что * не * в том случае, что parentViewController модального представления является навигационным контроллером в любом логическом смысле (page1Controller - это контроллер, запрашивающий модальный дисплей), поэтому почему Cocoa Touch настроил его таким образом? –

1

Я просто столкнулся с этой проблемой. Совершенно очевидно, что если вы поместите UIViewController, встроенный в NavigationController, тогда, когда из этого UIViewController вы представляете другой UIViewController по модулю, настоящий человек считает, что ведущим является NavigationController. Другими словами, parentViewController неверен.

Держу пари, что это ошибка: либо это, либо документация кажется неполной. Я спрошу.

1

Просто столкнулся с той же проблемой. Я считаю, что это ошибка. Мой сценарий следующий: Иерархия навигации с контроллерами вида A, B и C в этом порядке. На C есть кнопка, которая будет открывать контроллер модального представления, называемый D. После того, как D представлен, навигационный контроллер бросает C из своей иерархии, что является ужасным поведением. После того, как D будет отклонен, навигационный контроллер создает новый контроллер типа C и помещает его в свою иерархию для восстановления исходного. Грозный. Мое решение является взлом навигации по иерархии этот путь (очень плохое решение, но хорошо работает с массивом 2 размерности можно реализовать штабелирования модальности.):

- (void)presentModalViewController:(UIViewController *)c { 
    [self.navigationHierarchy removeAllObjects]; 
    [self.navigationHierarchy addObjectsFromArray:[navigation viewControllers]]; 
    [navigation setViewControllers:[NSArray array] animated:YES]; 
    [navigation presentModalViewController:c animated:YES]; 
} 

- (void)dismissModalViewController { 
    [navigation dismissModalViewControllerAnimated:YES]; 
    [navigation setViewControllers:[NSArray arrayWithArray:self.navigationHierarchy] animated:YES]; 
} 

Эти два метода определены, где я поддерживать основной навигации hiererchy: делегат приложения. навигационная и навигационная иерархия определяются следующим образом:

NSMutableArray *navigationHierarchy; 
UINavigationController *navigation; 
Смежные вопросы