View : accéder à son controleur ?
Brindavoine
Membre
Bonjour je bloque sur un probleme de débutant depuis plusieurs heures !!
Mon probleme par l'exemple :
Je crée un nouveau projet de type View Based Application.
J'ai donc de créé un MyAppDelegate et Un MyViewController
J'ai aussi un MainWindow.xib ainsi qu'un MyViewController.xib
Je rajoute simplement une classe custom pour ma view "CustomView" que le lie à la view dans interface builder de MyViewContoller.xib
Mon probleme : j'aimerais créé une propriété dans ma view qui pointe faire mon controler car j'aimerais m'en servir pour certaines actions comme delegate...
J'ai donc mis :
Comment linker la propriété delegate sur l'instance du controller??
Le controller étant le file Owner, j'ai essayé de mettre delegate ---> File's Owner en vain.
J'ai tenté aussi de créer dans IB un "object" de type MyViewController et de faire pointer l'outlet delegate vers celui ci, ca ne marche pas non plus...
Comment faire ?
Mon probleme par l'exemple :
Je crée un nouveau projet de type View Based Application.
J'ai donc de créé un MyAppDelegate et Un MyViewController
J'ai aussi un MainWindow.xib ainsi qu'un MyViewController.xib
Je rajoute simplement une classe custom pour ma view "CustomView" que le lie à la view dans interface builder de MyViewContoller.xib
Mon probleme : j'aimerais créé une propriété dans ma view qui pointe faire mon controler car j'aimerais m'en servir pour certaines actions comme delegate...
J'ai donc mis :
#import <UIKit/UIKit.h><br /><br />@interface CustomView : UIView {<br /> // Delegate<br /> IBOutlet id delegate;<br />}<br /><br />@property (assign) id delegate;<br /><br />@end
Comment linker la propriété delegate sur l'instance du controller??
Le controller étant le file Owner, j'ai essayé de mettre delegate ---> File's Owner en vain.
J'ai tenté aussi de créer dans IB un "object" de type MyViewController et de faire pointer l'outlet delegate vers celui ci, ca ne marche pas non plus...
Comment faire ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Ah si, le terme delegate est ici mal choisi, car la fonction d'un delegate est bien précise en Obj C.
Par contre pour ton souci, tu as juste a ajouter un attribut IBOutlet MyViewController* et faire le lien avec IB, ya pas de raison que ça coince.
Mon programme est en fait plus complexe et c'est sûrement de là d'ou viens l'erreur :
Je me sert en fait de ma CustomView comme classe abstraite qui sert de base à deux vues : la vue portrait et la vue landscape qui ne font que surcharger les méthodes de dessin... (car j'ai deux affichages possibles, cf mon post de validation d'architecture)
donc ce n'est pas directement CustomView que je lie dans IB mais PortraitView (qui est appelée par défaut. (je ne switche pas encore entre les deux, ce sera sûrement pour une prochaine question...)
Quand je place un NSLog(@controller : %@,delegate); dans la méthode drawRect, de PortraitView c'est impeccable, mais lors de l'init qui est géré par la classe abstraite customView, j'ai toujours null"...
Et j'ai justement besoin de mon controller lors de l'init car c'est lui qui fait lien avec mon model...
[UIApplication sharedInstance].delegate.myViewController
De cet manière tu y a accès de partout et sans avoir à refaire le lien vers le delegat quand tu va changer ta vue entre les deux passages.
Le probleme proviens de l'odre d'exécution. J'essayais d'obtenir le controller depuis l'initialisation, ors celui ci n'était pas encore défini...
si j'ajoute à l'exemple de Philipe :
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super initWithCoder:coder]) {
NSLog(@controller depuis coder : %@",controller);
}
return self;
}
Cela ne fonctionne pas...
Bon, ben je vais simplement organiser mon code autrement.
Merci en tt cas
- chaque instance que tu as dans ton XIB est créée et initialisée, donc reçoit un appel à init... (initWithCoder / initWithFrame / initWithNibName:bundle: / init ... selon le type d'objet et le contexte, voir autres sujets sur le forum pour plus d'infos)
- une fois que toutes les instances sont créées et initialisées, les connections (IBOutlets) sont réalisées. Il ne peut les faire qu'après, bien évidemment, puisque tu peux très bien avoir dans l'objet A un IBOutlet vers l'objet B, mais si l'objet B n'est pas encore alloué et initialisé au moment de la création de l'objet A, il aura du mal à faire la connexion...
- Une fois que tout est fini et le NIB chargé, une méthode est appellée à la fin de tout ça. Sous Mac c'est awakeFromNib, sous iPhone on utilise plus souvent viewDidLoad pour les initialisations post-chargement de NIB.
C'est pour ça que ces IBOutlets ne sont pas encore connectés (donc valent nil) dans le init, ils ne sont pas encore "prêts".
Je constate qu'Apple fait donc:
Une initialisation de base et ensuite seulement les liens. Est-ce propre? N'y a t'il pas un risque "d'oublier" de faire les liens?
En soit comment veux tu pouvoir en oublier ? Lorsque le xib est chargé, toute les instances sont créé puis les valeurs sont assigné et les "lien" fait.
Quand tu le fait en code c'est la même chose, tu crée ton objet, le règle, le place dans ta vue et garde une référence dessus pour éventuellement la pacer à un autre objet.
Qu'est-ce qui te chagrine dans ce process ?
Au lieu de:
C'est pas le fait de rajouter une ligne n'y le risque d'oublier la deuxième en fait, c'est juste que j'ai l'impression que l'architecture de mes classes n'est pas bonne lorsque je suis obliger de faire ça.
Imagine exemple type, que tu aies besoin de faire des références croisées (finalement c'est courrant du moment qu'il n'y a pas de retain loop, donc qu'un des 2 soit assign et pas retian), comme un ViewController A qui possède une View B, qui elle-même a une variable "delegate" pointant en fait sur A (exemple type d'ailleurs).
Tu fais comment avec ta solution ? Tu crées A en lui passant B directement... ah mince B n'existe pas encore. Bon tu crées B avant alors, puis tu crées A en lui passant B. Au oui mais mince quand tu crées B faut lui passer A... oups :P
De toute façon vu que : (1) ce genre de cas peut arriver et (2) Lorsque tu désarchives un XIB il ne peut pas savoir les méthodes non-standard (genre initWithUnTruc) qui sont disponibles pour initialiser ton objet directement en passant des paramètres, bah le désarchivage du XIB ne peut pas s'y prendre autrement que d'abord faire des init/initWithCoder/initWithFrame (qui sont des méthodes standard, elles), et ensuite affecter les variables (IBOutlets).
Merki
Après avoir lu ce post j'ai voulu revoir un peu mon organisation Controller/Views pour faire quelque chose de plus propre.
Ceci semble fonctionner sauf que ma View chargée par le controller ne reprend pas les éléments que j'ai placé à la main dans IB.
Voici mon code et mes liens IB:
Quand je charge mon controller j'obtiens bien:
2009-07-22 16:48:23.724 myPocketApp[14107:20b] init view Sujet
2009-07-22 16:48:23.726 myPocketApp[14107:20b] init view Sujet3
Voici comment tout ceci est relié sous IB:
UIViewController: APPCLASSIQUECONTROLLER
UIView : APPCLASSIQUEVIEWS
Résultat dans mon simulateur: mon UIView APPCLASSIQUEVIEWS est bien affichée mais les éléments que j'ai ajouté sous IB (le textView et le bouton) n'apparaissent pas en revanche le background est bien rouge.
C'est la première fois que j'essaie d'organiser mon programme de cette manière. Qu'ai-je oublié?
merci
Toi ce que tu as fait, c'est remettre une deuxième vue par dessus, du coup elle cache la bonne
En fait oui je la remet par dessus car je ne comprennais pas pourquoi elle n'était pas appelée direct au chargement de mon controller alors que j'avait relié le View de mon controller sous IB à appClassiqueViewS (elle n'était pas appellée car j'avait aucun log en console et un écran blanc au lieu de rouge).
Ceci est corrigé en ajoutant :
Du coup si je veux chopper mes autres vues crées par IB je devrais pouvoir le faire avec ce que tu as dit: [self view].
merci pour l'aide
a+
question supprimée car j'ai trouvé la solution
Ca coincait chez moi jusqu'à ce que je mettre des #import "moncontroller.h" @class moncontroller dans le header de ma vue et #import "mavue.h" @class mavue dans le header de mon controleur.
Quelqu'un peut m'expliquer à quoi sert de @class ?
#import sert à importer les méthodes et attributs d'une classe externe mais le @class?
EDIT2: question déjà posée ici:
http://www.osx-dev.com/index.php?topic=3308.0
Le #import est "brutal" il importe tout le code associé. Alors que le @class sert juste à dire au compilo, "t'inquiète la classe existe bien, il a le droit de s'en servir" mais au final il ne sait pas ce qu'il y a dedans, au contraire d'#import.
Sinon à propos de ton code, peut être que je me trompe, mais ta vue ne voudrais tu pas plutôt l'associé à l'attribut "view" de ton controller, plutôt que de créer un autre attribut?
[edit] tu es réactif dit donc ^^, c'est vrai que je me rappelait avoir déjà posé la question
J'ai une autre question à ce propos. Si on se retrouve à faire l'initialisation est deux fois donc et que la deuxième partie se trouve pas mal après. Ca ne risque pas de créer un souci avec le dealloc? Ne peut-on pas se retrouver à désallouer quelques qui n'existe pas encore?
La solution que je verrais c'est de créer un faux objet quand même à l'initialisation. Ou bien d'avoir une grande confiance dans son code ;-)
En gros si je fait:
Or dans le dealloc de MaClass, je release le truc nécessaire mais pas dispo avant. Ya pas un risque que le dealloc soit appelé trop tôt (avant le setUnTrucNecessaire...) et que du coup j'ai un release sur quelques choses qui n'existe pas.
Purée je suis désoler mais j'ai du mal à exprimer mon truc.
Et si c'est à 2 endroits séparés, bah si ton unTruc n'était pas créé avant, il va valoir nil, donc l'envoi du message dealloc à nil n'aura aucun effet.
Bref j'ai du mal soit à voir le use case auquel tu penses, soit à voir comment il peut arriver.
donc var = nil et [var release] c'est très différent.
Et oui, var = nil et [var release] sont très différents, le premier utilisé seul aboutissant à une fuite de mémoire généralement, sauf quand on programme pour Leopard avec le garbage collector activé.