[SWIFT] AppDelegate, Push et redirection sur la bonne vue ?

Bonjour tout le monde,
Je bloque sur un petit problème, ça m'a pas l'air compliqué mais je pense que j'ai juste pas la bonne façon de faire, la bonne logique..
En gros, je reçois une notification push avec des données dedans..
Lorsque je reçois une notification "NouveauMessage" :
- Si je suis sur le bon controller, j'actualise les nouveaux messages (pas de soucis, ça fonctionne bien ^^)
- Si je ne suis pas sur le bon controller, j'ai une bannière qui descend, au tap sur ma bannière, je souhaiterai rediriger vers le bon contrôle (ma discussion)
En cherchant un peu, je me retrouve avec ça (dans AppDelegate)
Lorsque je clic sur ma bannière qui descend pour prévenir qu'il y a un nouveau message :
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) // j'appel mon storyboard
let DiscussionController = mainStoryboard.instantiateViewController(withIdentifier: "Discussion") as! DiscussionController
self.window?.rootViewController = DiscussionController
self.window?.makeKeyAndVisible()
J'arrive bien à afficher la bonne conversation sauf que je n'ai plus ma barre de navigation en haut, j'ai seulement le controller..
Comment faire pour afficher aussi la barre de navigation ?
Je me doute qu'il me manque une ligne de code quelque part mais je ne sais pas quoi mettre et vu que c'est la première fois que je test ça, je bloque un peu..
Merci de votre aide
Réponses
Bon du coup, j'ai réussi à récupérer la barre de navigation comme ça :
Sauf que je perds une action assez importante dans cette barre de navigation..
Le bouton "retour"
Le code de mon bouton retour est juste un :
dismiss(animated: true, completion: nil)
Vu que je n'arrive plus par le chemin "normal" (via le segue), que j'affiche cette vue via la notification, c'est normal qu'il n'ai rien à "dismiss"..
Du coup, je pense que je m'y prends mal quelque part..
Une idée ?
Plutôt que de remplacer le controller principal de la fenêtre, cela me semblerait plus judicieux de présenter la nouvelle discussion au dessus du contexte actuel (une modal sheet par ex). Si tu remplaces le controller principal,
dismiss
ne pourra pas fonctionner, car le receveur de cette fonction doit être un controller "présenté".Donc plutôt que:
Tu peux faire:
Et pour voir ton bouton back, il faut en effet le définir à la main car tu es hors du "flux normal de navigation" (tu en crées un nouveau en fait, donc normal de ne pas avoir de back pour le premier élément).
discussionController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: self, action: dismissCurrent(_:))
Et je te laisse l'implémentation de
dismissCurrent
comme exerciceAttention aux conventions: les noms d'instances doivent commencer par des minuscules.
Quand on lance l'appli, il y a un système qui fait que le storyboard principal ("Main.storyboard" par défaut) est chargé et le View Controller mis en "Initial View Controller" est instancié et placé dans window.rootViewController.
Dans ton cas, tu as dû mettre le Navigation Controller en "Initial View Controller", et le DiscussionController pour son contenu.
Pourquoi ce que tu fais ne marche pas: parce que tu instancies un nouveau DiscussionController et que tu demandes à ce qu'il devienne window.rootViewController.
Ce qui faut faire: obtenir des références vers les objets qui ont été instanciés:
Cette manière de faire — accéder aux objets en connaissance de leur hiérarchie — est loin d'être élégante mais c'est bien ainsi qu'Apple propose de faire.
C'est ce que je me suis dit aussi et j'avais testé cette façon de faire avec :
Sauf que je me retrouve avec :
Ce qui est bizarre c'est qu'il parle de LoginController alors que je suis plus dessus mais sur mon HomeController
Ouai c'est ce que je me suis dit, je suis "hors du flux normal de navigation" et que j'partais n'importe comment.. d'où mon post ici ^^
Ok, j'ai donc mis ça dans mon AppDelegate pour garder une reference dessus :
J'ai pas compris pourquoi tu met le reste dans didFinishLaunchingWithOptions, je suppose que c'est juste pour l'exemple (où j'ai loupé un truc) ?
J'ai fais le test en le mettant sur le tap sur ma bannière qui descend quand il y a un nouveau message et je me retrouve avec cette erreur :
et la ligne 260 est :
Je patauge
Nous n'avons pas ton code et nous ne savons pas comment sont organisés tes View Controllers.
Non, c'est parce qu'il faut le faire à un moment où on sait que le storyboard a été lu et ses objets instanciés.
Pour faire un parallèle: on accède aux outlets dans viewDidLoad() parce qu'on est sûr à ce moment que la vue est chargée ainsi que ses vues enfants, et que les outlets pointent bien vers les objets.
Encore une fois, je ne connais pas la hiérarchie de tes view controllers. J'ai supposé que le navigationController était le rootViewController. Forcément, si ce n'est pas le cas et que tu écris:
et que le rootViewController n'est pas un UINavigationController, alors ça renvoie nil.
Ok je vois, du coup je laisse ça ici.
J'arrive sur LoginController, pour m'identifier, ensuite j'affiche mon HomeController (via un segue)..
Et à partir de là, j'aimerai pouvoir afficher n'importe quel controller..
Mais du coup je ne sais pas quoi mettre à la place de :
navigationController = window.rootViewController as? UINavigationController
Cette partie là n'est pas clair pour moi
Est-ce-que je peux redéfinir un nouveau rootController par exemple ?
Peut-être qu'un fois que je suis connecté et que je passe par le segue pour aller sur mon HomeController, je peux changer le rootController (remplacer LoginController par HomeController) et ainsi pouvoir régler le problème de :
nan ?
(je sais pas si c'est possible, si ça apporter d'autres soucis ou si je pars pas dans la bonne direction mais je vais quand même allé tester..)
Oui, mais, tu ne dois pas. Le rootViewController est déjà défini par ton Main.storyboard. C'est le view controller marqué en "Initial View Controller", celui avec une flèche.
Donc, le rootViewController est un LoginController ?
Disons qu'habituellement on ne fait pas ainsi, parce qu'on a rarement besoin de s'identifier.
Typiquement, on a un UITabBarController à la racine. Aussi, on va plutôt afficher le LoginViewController en modal plein écran quand c'est nécessaire — par exemple au premier lancement.
Pourquoi ?
Une fois que je suis connecté, je n'ai plus besoin de lui..
Et si je relance l'appli, il redevient le rootViewController
Je suppose que j'ai pas la bonne vision du truc ^^
Du coup, j'ai vérifier via le code et oui, c'est bien LoginController (et c'est aussi lui qui a la flèche)
Donc je devrais plutôt arriver sur mon HomeController (mettre la flèche dessus) et si je ne suis pas connecté, j'affiche la page de connexion ?
L'appli aura sans doute une option pour se déconnecter, et il faudra alors demander à se reconnecter.
L'utilisateur ne se connecte pas à chaque lancement. Tu vas conserver les identifiants dans le Keychain.
Oui, c'est une fonctionnement plus classique.
Pour revenir à ton problème:
dans l'AppDelegate, tu vas donc récupérer une référence vers un HomeController (et pas un UINavigationController).
Ensuite, tu surchargeras la méthode prepareForSegue() du HomeViewController, afin de récupérer des références vers ses view controllers enfants.
Pour le coup si..
C'est pas pratique mais c'est comme ça (et quand ça va les souler de se connecter à chaque fois, ils vont me demander si c'est pas possible de rester connecter, j'le vois venir gros comme une maison ^^)
Bon, je vais commencer par faire cette modification là..
Je reviendrais pour tester la suite après