2010-11-27 2 views
1

У меня возникли проблемы с ссылкой на один контроллер вида из другого. Код работает, но я получаю предупреждения, которые заставляют меня думать, что я ошибаюсь. Я пытаюсь перезагрузить данные в tableView, чья controller находится в NavigationController.
Что случилось с сообщением вроде этого:Правильно перемещается иерархия ViewController?

Из AppDelegate:

[self.tabBarController.selectedViewController.topViewController.tableView reloadData];

Хотя это работает, я получаю предупреждение request for member 'topViewController' in something not a structure or union потому что Xcode не знает, что selectedViewController возвратит navigationController. Так что я мог бы сделать следующее:

UINavigationController *myNavigationController = self.tabBarController.selectedViewController; 
[myNavigationController.topViewController.tableView reloadData];

Но тогда я получаю это предупреждение: incompatible Objective-C types initializing 'struct UIViewController *', expected 'struct UINavigationController *'

Как далеко я должен пойти с этим? Первая строка работает. Чтобы добраться до «правильного пути», он возьмет 8 строк кода?

ответ

4

Основной код запаха здесь, ИМО. Вы пытаетесь сделать действие на (большом) расстоянии. Не совсем ясно, что вы пытаетесь выполнить, и почему вам нужно сделать это действие с делегата приложения. Я видел, как некоторые разработчики рассматривают делегата приложения как гигантский глобальный кусок грязи, и я думаю, что это анти-шаблон, который следует исключить из разработки iOS.

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

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

+0

Я вижу вашу точку зрения. Событием, инициирующим это действие, является файл, переданный приложению из другого приложения через `application: handleOpenURL`. Если я решаю вызвать метод в моем «tableViewController», чтобы позволить ему обрабатывать это действие (что звучит как хорошая идея). Мне все равно придется ссылаться на `tableViewController` из` AppDelegate` один раз. Я часто сталкиваюсь с этой дилеммой, а не только по этой проблеме. Кажется, я постоянно храню один объект как свойство в другом, до такой степени, что это просто паутина. Вот почему я пытался использовать эту начальную строку кода, чтобы этого избежать. – Andrew 2010-11-27 07:49:36

2

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

Вы можете использовать точечную нотацию с кучей преобразования типов (который в данном случае является чудовищно уродливый):

[((UITableViewController *) ((UINavigationController *) self.tabBarController.selectedViewController).topViewController).tableView reloadData]; 

Или вы можете разбить его на отдельные шаги:

UINavigationController *navController = (UINavigationController *) self.tabBarController.selectedViewController; 
UITableViewController *tableViewController = (UITableViewController *) navController.topViewController; 
[tableViewController.tableView reloadData]; 

Обратите внимание, что я предполагаю, что ваш верхний VC является подклассом UITableViewController.

Вы действительно не должны получать доступ к свойству .tableView извне - вы должны инкапсулировать это поведение с помощью метода reloadData на сам контроллер просмотра. Даже если все, что он делает, это позвонить reloadData на свой .tableView, вы должны его инкапсулировать. Это сделает ваш код более модульным (что упрощает понимание для вас и других), а также упрощает расширение и добавление сложности в контроллер View вниз по дорожке.

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

+0

Awesome. Ваш код работал. Мне было интересно, как я могу работать в этих сообщениях. Я рассмотрю как предложение reloadData, так и, возможно, использование Notifications as Shaggy Frog. – Andrew 2010-11-27 07:57:33

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