2010-11-27 5 views
1

Je n'arrive pas à référencer un contrôleur de vue d'un autre. Le code fonctionne mais j'ai des avertissements qui me font penser que je vais mal. J'essaye de recharger les données dans un tableView dont controller est dans un NavigationController.
Quel est le problème avec un message comme celui-ci:Traverser la hiérarchie ViewController correctement?

De l'AppDelegate:

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

Bien que cela fonctionne, je reçois l'avertissement request for member 'topViewController' in something not a structure or union parce Xcode ne sait pas que le selectedViewController retournera un navigationController. Donc, je pouvais faire ce qui suit:

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

Mais j'obtenir cet avertissement: incompatible Objective-C types initializing 'struct UIViewController *', expected 'struct UINavigationController *'

Jusqu'où dois-je aller avec ça? La première ligne fonctionne. Pour arriver à la "bonne manière", est-ce que ça va prendre 8 lignes de code?

Répondre

4

Une odeur de code majeur ici, IMO. Vous essayez de faire de l'action à une (grande) distance. Vous ne savez pas exactement ce que vous essayez d'accomplir, ni pourquoi vous devez effectuer cette action à partir du délégué de l'application. J'ai vu des développeurs traiter le délégué de l'application comme une boule de boue géante, et je pense que c'est un anti-pattern qui devrait être éliminé du développement iOS. Retour à votre question: vous essayez de forcer un contrôleur de vue de table, à l'intérieur d'un contrôleur de vue à onglets, à recharger ses données. Je suppose que c'est en réponse à quelque chose qui se passe. Pourquoi ne pas avoir le contrôleur de vue en charge de cette table qui surveille cet événement au lieu du délégué de l'application? De cette façon, la chose qui possède la vue de la table la contrôle directement - ce qui est le point entier du modèle MVC. Il s'agit d'une approche beaucoup mieux que de faire descendre le délégué de l'application à travers une hiérarchie pour trouver une vue de table ... en termes de complexité, de lisibilité et de fragilité.

Si, pour une raison ou une autre, vous ne pouvez ou ne voulez pas que le contrôleur observe directement l'événement (difficile à comprendre pourquoi), vous pouvez toujours demander à l'application de publier un NSNotification en charge du registre de la table en tant qu'observateur. Pas aussi bon que l'observation directe, mais certainement meilleur que votre approche actuelle.

+0

Je vois ce que vous voulez dire. L'événement qui initie cette action est un fichier transmis à l'application depuis une autre application via 'application: handleOpenURL'. Si je décide d'appeler une méthode dans mon tableViewController pour la laisser gérer cette action (ce qui semble une bonne idée). Je dois toujours référencer le 'tableViewController' de la' AppDelegate' une fois. Je rencontre souvent ce dilemme, pas seulement par rapport à ce problème. Il semble que je stocke constamment un objet comme une propriété dans une autre au point où c'est juste une toile d'araignée. C'est pourquoi j'essayais cette ligne de code initiale, pour éviter cela. – Andrew

2

Vous ne pouvez pas utiliser la notation par points sauf si le compilateur connaît le type d'objet sur lequel vous l'utilisez et que ce type d'objet peut recevoir un message avec ce nom.

Vous pouvez utiliser le notation avec un tas de types-moulages (dans ce cas, est affreusement laid):

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

Ou vous pouvez le diviser en étapes distinctes:

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

Notez que je suppose que votre VC supérieur est une sous-classe de UITableViewController.

Vous devriez vraiment pas être à l'extérieur de la propriété accédez .tableView - vous devez résumer ce comportement avec une méthode reloadData sur le contrôleur View lui-même. Même si tout ce qu'il fait est appelez reloadData sur son .tableView, vous devriez l'encapsuler. Cela rendra votre code plus modulaire (ce qui le rendra plus facile à comprendre pour vous et les autres), et rendra plus facile le développement et ajoutera de la complexité à votre View Controller en bas de la piste.Sans savoir exactement comment cette application est structurée, je suppose que vous êtes probablement mieux d'utiliser des notifications ou des observateurs pour obtenir votre VC pour recharger ses données. Si vous avez un événement global qui nécessite une actualisation de l'interface utilisateur, un NSNotification est un bon moyen de faire en sorte que la couche d'interface utilisateur reçoive le message tout en gardant votre code sympa et modulaire.

+0

Génial. Votre code a fonctionné. Je me demandais comment je pourrais travailler le typecasting dans ces messages. Je considérerai à la fois la suggestion 'reloadData', ainsi que l'utilisation possible de Notifications comme Shaggy Frog. – Andrew

Questions connexes