[Résolu] Un delegate perso dans un PageViewController
Bonjour,
mon soucis est que je ne parviens pas à exécuter une fonction qui se trouve dans mon container général, à partir d'un UIPageViewController.
Alors que j'y arrive très bien à partir d'un simple UIViewController.
Voici ma fonction :
Il s'agit de faire une barre perso, qui soit partout la même
// NavBar
func configureNavbar(etapeViewController: UIViewController) {
etapeViewController.navigationItem.setHidesBackButton(true, animated: false)
var fixedSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
fixedSpace.width = 36.0
var addPatientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "addButton.png"), style: .Plain, target: self, action: "nouveauPatient")
addPatientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
var newPatientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "patientsButton.png"), style: .Plain, target: self, action: "togglePatients")
newPatientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, addPatientsButton, newPatientsButton]
println("configureNavbar - \(etapeViewController)")
}
Lorsque j'appelle cette fonction, à partir de mon UIViewController (Etape0ViewController), à l'aide de :
delegateEtape0?.configureNavbar?(self)
dans le viewDidLoad (ou autres, d'ailleurs), ça fonctionne parfaitement.
Lorsque j'appelle la fonction à partir de Etape1ViewController (qui est le controller maà®tre des sous-pages du UIPageViewController), la fonction n'est pas appelée.
J'ai essayé de placer l'appel de la fonction, dans tous les ViewControllers (maitre, sous-page, et classe de référence - le fameux content), et rien n'y fait.
Si quelqu'un a une idée, parce que là , je suis carrément bloqué, ça fait trois jours que je tourne en rond.
Merci d'avance.
Réponses
C'est vraiment un truc tordu.
J'ai même essayé de placer mon appel de fonction à la création des controllers.
Et rien ne se passe. Pfff.
Car quand tu fais "delegateEtape1?.configureNavbar?(controller)" la méthode n'est appelée :
- Que si "delegateEtape1" n'est pas nil (c'est pour ça que tu écris "?." pour dire "s'il n'est pas nil, appelle configureNavBar", c'est ça que veut dire cette syntaxe)
- Que si la méthode congigureNavBar est implémentée (c'est pour ça que tu écris un point d'interrogation dans "configureNavbar?(controller)", pour dire "appelle la méthode si la méthode existe" (certainement car dans ton protocole tu l'as mis en "optional" ce qui fait qu'elle peut tout à fait ne pas être définie dans l'objet que tu as dans ta variable "delegate1")
Ok, merci AliGator pour tes remarques.
Je t'avoue que ces histoires de optionnal, de "?", et de "!", ça me saoule un peu, mais bon, il faudra bien qu'un jour je comprenne vraiment.
En attendant, j'ai fait ça, et tout un tas de bidouilles autour de ce truc, et ça ne fonctionne pas.
J'ai viré le "optionnal" de la méthode dans le protocole
Je crée mon delegate
Et j'appelle la méthode
Et ça ne fonctionne pas
J'ai essayé toutes les combinaisons possibles...
Je fais comme là , par ex.
Ma façon de faire (avec optionnal) fonctionne parfaitement à partir d'un simple controller, donc je ne m'explique pas pourquoi elle ne fonctionne pas dans le cas d'un PageView.
ça, c'était un essai à la création des pages
Mais, si je fais comme dans le cas d'un simple controller, c'est dans le viewDidLoad, et c'est ainsi que ça fonctionne
Mais là , rien n'y fait.
Quand tu dis
Je comprend, et je supprime le "optionnal" et le "?"
Mais quand tu dis
Alors là , je comprend rien
J'essaie ça
ou ça
ça déconne
à‰videmment en adaptant l'appel de la fonction
Enfin bref, j'y comprend rien, mais ça fonctionne dans un simple controller et pas dans un pageView
Merci pour tes précisions, mais je suis carrément dégouté par ce truc.
ça doit être mon côté codeur de base autodidacte.
Je suis pourtant plutôt matheux, et j'adore les concepts, mais là , je suis bluffé. Peut-être un peu trop présomptueux sur mes compétences.
Si t'as une autre idée, je suis preneur. Merci
Concernant les déclarations, je fais ça
Puis dans le viewDidLoad (ou autre part) je fais ça
Et ça marche nickel
Pourquoi ça ne fonctionne pas pour un delegate dans un pageView
et dans le viewDidLoad (ou autre part)
xCode me met une erreur
C'est débile, non ?
Et surtout que d'habitude, dans un simple controller, je n'ai pas de soucis pour le delegate en faisant comme ça
Puis
Puis dans le viewDid........
Y'a un truc qui m'échappe
Bon, je suis convaincu que ta piste est la bonne.
Et comme je sais, que souvent, le problème n'est pas unique, mais multiple, j'essaie de ne pas m'entêter, et donc j'ai essayé ça.
Puis, parce que cela ne peut être que ici, à mon avis (l'appel de la méthode)
avec ou non le "!"
Pas d'erreur, mais ça plante et j'ai ce message habituel
ça sent grave les histoires de déclaration, de optionnal, de nil, de "?", de "!"
Et si je fais
Et ça
Donc, avec des "?", ça ne plante pas, mais cela ne fonctionne pas. La méthode n'est pas appelée.
Oula.
Merci Ceroce pour ta remarque certainement judicieuse, car je n'y ai pas pensé du tout. D'ailleurs, je vais mettre du temps à la comprendre.
à‰coute, je fais quelques essais avec ta remarque et je reviens.
ça me semble une super idée. Merci.
Bon, je t'avoue que je n'y comprend plus rien.
Je suis sur que c'est ta remarque qui pointe sur le problème.
Mais je m'emmelle les pinceaux entre les delegate des controller et mes propres delegate.
Par ex, (j'ai essayé avec et sans), je n'utilise pas UIPageViewControllerDelegate et pageController.delegate = self
car je ne vois pas la différence.
D'autre part, j'ai essayé ton truc, un peu partout, et j'ai toujours cette erreur
Je te met un fragment de code, que tu dois connaà®tre, car issue d'un tuto bien connu.
Je laisse toutes les tentatives en commentaires, ainsi, tu vois mes essais, et surtout mes lacunes d;-)
Désolé pour le code en vrac.
Puis
Merci d'avance pour tes futures réprimandes méritées
Et si je fais
j'ai cette erreur
booouuuuhhh, je vais pleurer ::)
Dans ton cas, une instance de UIPageViewController délègue son fonctionnement à une instance de Etape1ViewController.
1) Il faut dire au délégateur qui sera son délégué:
2) Le délégateur va appeler des méthodes sur son délégué. Il est donc nécessaire de formaliser ces méthodes. C'est le rôle du protocole UIPageViewControllerDelegate qui définit ces méthodes. La doc d'Apple explique dans quelles circonstances ces méthodes sont appelées par le délégateur.
De ton côté tu dois dire que Etape1ViewController se conforme à ce protocole; c'est à dire qu'il promet qu'il va implémenter ces méthodes.
3) Tu implémentes les méthodes voulues dans Etape1ViewController et elles doivent être appelées.
Franchement, j'ai donné pas mal de formations à iOS, et ceux qui n'avaient jamais étudié le développement iOS trouvaient la délégation simple, alors que ceux qui s'y étaient essayé avant trouvaient ça compliqué!
En fait, c'est réellement simple, il n'y a que deux objets. Fais un diagramme, tu verras.
Hummmm, merci Ceroce.
ça me rassure énormément que tu sois formateur iOs, ainsi, tu es donc sur de ton coup, et je vais te suivre.
Vu, que sur un simple controller, je n'ai aucun soucis avec les delegate, j'étais convaincu d'avoir tout compris, mais effectivement, dans le cas ou il existe déjà un protocole associé, genre pour tableView ou pageView, et que je doive utiliser le mien, ça se complique.
Mais tu dis plus haut
et là , tu dis
En gros, je dois dire que le delegate du pageView est mon delegate (delegateEtape1 plutôt que delegateEtape0) ou bienqu'il est le controller maà®tre (des sous-pages du pageView) : cad etape1ViewController ?
Et, hormis cela, si je comprend bien l'histoire, je dois
avec
jusque là , pas de problème, mais ce que je ne comprend pas, c'est que je doive implémenter
alors que je n'en ai pas besoin, et que j'ai simplement besoin de la mienne.
ça me perturbe tout cela :
Dire à iOs : Je prend les méthodes de pageView, je dois les implémenter, mais ne les utilise pas, et utilise la mienne. Oulala, ça devient torturé comme truc, non ?
D'autant plus que sur un simple controller, ça marche nickel, je ne comprend pas.
Tu as certainement raison quand tu dis cela :
mais le soucis n'est pas tant d'implémenter ses propres delegate, mais de le faire quand il y en a déjà qui existe (pageview).
Bon, je vais creuser, mais tout ça me semble super complexe, alors que, comme tu dis, cela me semblait super simple.
J'ai pris une grande respiration, et je vais donc essayer de formaliser ce que tu m'as expliqué.
Sur un simple controller, je crée mon délegate, et je lui dis de l'utiliser. ça fonctionne parfaitement.
Sur un controller qui a déjà des méthodes associées (joignables par son delegate), je dois lui dire :
1- Je me met sur ton delegate
2- J'implémente tes méthodes - Parce que y'a pas le choix quand on se met sur un delegate
3- Je lui dis que son delegate, il se le met dans la poche, et il prend plutôt le mien.
C'est carrément débile. On ne peut pas lui dire directement, qu'il prenne mon delegate (comme pour un simple controller), et donc, que ce ne soit pas nécessaire de demander de promettre ses méthodes à l'aide de
Oups, je suis en train de devenir fou.
Mais dis moi, si c'est bien comme cela que ça fonctionne, et alors, j'arrête de m'entêter et je poursuis selon tes conseils.
Mais j'aime bien comprendre quand je sens une contradiction, même si c'est logique pour les pros.
Encore merci pour tes efforts. Je sais que je suis dur de la feuille. N'empêche, tu m'as ouvert une énorme voie...
Je ne voyais pas les choses comme ça. Je croyais que c'était beaucoup plus binaire, ce truc.
Quand tu parle d'un délégué perso, c'est un objet de quel type ? Une classe déjà existante avec des contraintes particulières, ou un objet entièrement à toi ? Si c'est vraiment à toi, tu peux te passer de toute la syntaxe des délégués, et faire ça simplement.
Le système de MVC que je t'avais expliqué, c'étais aussi une sorte de délégué (dans l'esprit), mais codé plus simplement.
Merci Draken, pour ta remarque.
Ben non, regarde le début de mon post.
C'est juste pour appeler une méthode à la con qui est dans mon container général.
Je ne peux l'appeler qu'à partir d'un delegate comme expliqué plus haut.
Et j'y arrive sans problème à partir d'un simple controller, mais pas à partir d'un pageViewController
Jamais touché à un pageViewController de ma vie !
ok AliGator, mais tu as vu, j'ai tout essayé...
J'ai beaucoup de difficultés à comprendre ce que tu cherches à faire.
Le fait qu'une classe se conforme à un protocole ne l'empêche pas de se conformer à d'autres protocoles. Un objet peut donc être le délégué de plusieurs objets de classes diverses.
Je crois qu'à ce stade, il faut que tu lâches ton clavier, et que tu dessines tes objets:
- qui délégue à qui ?
- qui se conforme à quel protocole ?
je suis allé voir pour la énième fois la page apple du délestage pageview, et il s'agit de méthodes en relation avec le passage d'une page à l'autre (sous-pages, dirais-je), mais moi, c'est pas ça du tout, je veux juste appeler une méthode perso qui n'est pas dans mon controller (mais dans mon container général). Et cela, je peux le faire à partir d'un simple controller, mais pas à partir d'un pageview.
Donc tu ne peux pas "instancier un protocole", au sens "créer un objet directement de ce type" avec "Etape1ViewControllerDelegate()". Il faut créer une instance d'une classe concrète se conformant à ce protocole
C'est un peu comme si tu avais un protocole appelé "UnTrucQuiSaitRouler", protocole définissant la signature pour une méthode "func rouler()". Ce n'est qu'un protocole, tu ne peux pas directement créer un objet "UnTrucQuiSaitRouler()" car tu ne dis pas ce que c'est que ce truc, ce n'est qu'un protocole qui décrit une interface, (mais pas d'implémentation). Par contre tu peux ensuite avoir des classes "Velo" et "Voiture", qui toutes 2 se conforment au protocole UnTrucQuiSaitRouler, et qui donc vont avoir une implémentation de la méthode "func rouler()". Et là tu pourras faire "Velo()" ou "Voiture()" pour créer un nouveau vélo ou une nouvelle voiture, qui se trouve être UnTrucQuiSaitRouler particulier.
Bah là c'est pareil, tu peux pas instancier "Etape1ViewControllerDelegate()" car "Etape1ViewControllerDelegate" est un protocole. Il faut que tu instancies une classe réelle, concrète (ou que tu fournisses un objet déjà existant, comme self ou comme le ViewController parent, etc).
Le problème qu'on essaye de t'expliquer, c'est que dans ton exemple avec Etape1, delegateEtape1 est nil, car tu as oublié de lui affecter une valeur, tu as oublié de l'affecter à un objet (une instance) qui effectivement sera le délégué qui va recevoir le le message configureNavbar. Il faut à un moment faire un "delegateEtape1 = unObjetSeConformantAuProtocole" pour lui dire QUI est ce delegateEtape1 à qui tu souhaites que le message configureNavbar soit envoyé, car pour l'instant tu ne lui as rien dit et il n'y a personne d'indiqué (nil) pour répondre au message.
Si ça marche pour Etape0 c'est sans doute parce qu'il y a du code (que tu ne nous montre pas) qui a affecté une valeur à ta propriété "delegateEtape0", ce qui fait qu'elle n'est pas nil comme c'est le cas pour delegateEtape1. Ou alors pour Etape0 tu l'as peut-être pas fait par code, mais peut-être que ce delegateEtape0 c'est un IBOutlet et que tu l'as connecté à un objet existant via Interface Builder, mais en tout cas lui il a une valeur, alors que la propriété delegateEtape1 n'a toujours aucune valeur (nil) car tu ne l'as affectée nulle part à un objet existant.
bon, je vais vous envoyer tout mon code, pare que là , je suis out.
Je ne sais plus comment expliquer l'histoire.
Merci pour vos effort, et en tout cas, je relis quotidiennement vos réponses, et cela me pousse à m'instruire d'avantage.
Code au prochain post.
Code propre et épuré des tentatives.
D'ailleurs je vais mettre tout le projet.
Dans un UIPageViewController, une page est représentée par une sous-classe de UIViewController. (Appelons-là Page1ViewController). Si quelque chose change sur cette page, c'est elle qui doit prévenir le contrôleur principal (MainViewController), pas le UIPageViewController.
Donc:
1) Définis un protocole Page1ViewControllerDelegate.
2) MainViewController doit se conformer à Page1ViewControllerDelegate et implémenter les méthodes que ce protocole définit.
3) Page1ViewController doit posséder une propriété 'delegate' de type Page1ViewControllerDelegate?. ça veut dire que Page1ViewController ne sait pas quel est le type exact du délégué, seulement qu'il se conforme au protocole.
4) MainViewController doit fixer cette propriété en passant 'self'. (puisque le délégué, c'est lui).
Désolé de ne pas fournir de code, mais je ne maà®trise pas encore assez Swift pour cela.
La logique n'est pas compliquée en soit, mais il faut l'avoir fait au moins une fois pour comprendre, et surtout il faut s'assoir et lire sur le sujet à tête reposée plutôt que la tête plongée dans le code.
Ok Céroce, pas de pb pour pas de code swift.
Je comptais vous envoyer mon projet, mais le pb est que il faudrait expliquer trop de chose pour la navigation provisoire et celle avec les swipe, etc...
Je vais donc poster du code, mais avant je ré-explique le bouzin.
En gros, il s'agit d'un projet ou on passe d'étape en étape.
Le tout est dans un container avec slideNav sur le côté - Vous connaissez les autos en questions. Container et fonction toggle, etc
La première étape (etape0) est associée à un simple controller avec inscription (champs et photos).
Dans cette étape, la barre de nav s'affiche bien (ok pour le delegate)
Ensuite on passe à l'étape suivante puis etc.
Le truc complexe est que toutes les étapes, sauf l'étape 0, sont des pageView, car elles ont des sous-étapes. En gros, on doit valider plusieurs écran par étapes, sauf pour l'étape 0.
On navigue au sein de chacune des étapes (sauf étape0) par le swipe naturel du pageview de chaque étape, puis on passe à l'étape suivante avec un UIPanGestureRecognizer perso
Donc, en gros, à partir de l'étape 0, je parviens à lancer la fonction
qui se trouve dans mon container général à l'aide de
lors du viewDidLoad
Mais dans le cas des etape1, ou les suivantes, cela ne fonctionne pas.
Je met ici le code complet de etape1ViewController qui est le controller maitre pour ses sous-pages qui sont Etape1L1, Etape1L2, etc.
Ainsi, ce sera plus clair, j'espère.
Merci d'avance
Ok AliGator pour ta remarque, je suis entièrement d'accord avec toi.
Mais tout ce que j'ai lu sur le sujet ne m'aide pas, car on y parle des delegate des tableView et autres (que je comprend parfaitement, car je les utilise), et lorsque l'on parle de ses propres delegate perso, on n'en parle jamais lorsque l'on veut les utiliser sur des trucs qui ont déjà leur delegate (tableview...), mais seulement dans le cas simple d'un simple controller. Avec protocol, etc. Chose que j'ai bien assimilé dans le cas de mon etape0, mais pour le reste (pageView) on est dans le flou total.
Maintenant si t'as un pur lien qui approfondit tout ça, je suis preneur, mais j'ai déjà lu des tonnes de pages sur les protocol et delegate.
Merci AliGator pour ton lien, mais malheureusement pour moi, il est en objC.
J'arrive à peu près à traduire, car j'ai commencé en objC, mais j'avoue que ça me parait encore plus confus.
Pour moi, le pb est simple :
Je sais faire un truc delegate / protocole (excuse ma terminologie) sur (je le répète) un simple controller, mais cela ne marche pas sur un pageview.
Donc, en gros, lorsqu'il existe déjà des méthodes associées via le delegate (excuse ma terminologie), comment faire qu'il prenne la mienne - Comme dans le cas d'un simple controller qui n'a pas déjà des méthodes associées via le delegate. Et dans ce cas, je le rappelle, je sais le faire.
On fait quoi, on squizze le delegate du pageView, puis on fait le sien perso, comme l'explique Céroce
ou bien on fait comme dans le cas d'un simple controller (chose que je maitrise), son propre delegate (comme dans ton tuto), et là , cela ne fonctionne pas dans le cas d'un pageView, et je suis sur que dans le cas d'un tableView, c'est la même.
Mon problème est pourtant simple :
Dans un cas (simple controller), ça marche, dans le cas d'un pageView, ça marche pas.
Il est ou le problème ?
C'est pas une histoire de concept ? Puisqu'il est assumé.
Désolé pour le ton de dépité, mais je suis vraiment découragé, car pour moi cela doit être évident.
Je sais faire un truc et je le comprend, et je n'y arrive plus dans un autre contexte, et surtout, je ne comprend pas pourquoi...
Dans le code posté je ne vois pas où est assigné la variable delegateEtape1 (tout comme Ali et Céroce te l'on dit). Cela me semble être un bon point de départ. Place un point d'arrêt sur:
et vérifie delegateEtape1 pour voir quel objet (et je parle d'objet pas de protocole) est assigné à cette variable. Si cette variable est à nil (ce qui semble être le cas) c'est qu'il manque la valorisation.
Si cela fonctionne avec un 'simple controller' vérifie dans ton projet comment et où est assigné delegateEtape0.