Ignorer un contrôleur de vue présenté


116

J'ai une question théorique. Maintenant, je lis le guide ViewController d'Apple .

Ils ont écrit:

Quand vient le temps de rejeter un contrôleur de vue présenté, l'approche préférée est de laisser le contrôleur de vue de présentation le rejeter. En d'autres termes, dans la mesure du possible, le même contrôleur de vue qui a présenté le contrôleur de vue devrait également prendre la responsabilité de le rejeter. Bien qu'il existe plusieurs techniques pour notifier au contrôleur de vue de présentation que son contrôleur de vue présenté doit être rejeté, la technique préférée est la délégation.

Mais je ne peux pas expliquer, pourquoi je dois créer un protocole dans le VC présenté et ajouter une variable de délégué, créer une méthode de délégué dans la présentation de VC pour rejeter le VC présenté, au lieu d'un simple appel dans la méthode de contrôleur de vue présentée

[self dismissViewControllerAnimated:NO completion:nil]?

Pourquoi le premier choix est-il meilleur? Pourquoi Apple le recommande-t-il?

Réponses:


122

Je pense qu'Apple se couvre un peu le dos ici pour un morceau d'API potentiellement volumineux.

  [self dismissViewControllerAnimated:NO completion:nil]

Est en fait un peu un violon. Bien que vous puissiez - légitimement - appeler cela sur le contrôleur de vue présenté, il ne fait que transmettre le message au contrôleur de vue de présentation. Si vous voulez faire quoi que ce soit au-delà du simple rejet du VC, vous aurez besoin de le savoir, et vous devez le traiter à peu près de la même manière comme une méthode déléguée - car c'est à peu près ce que c'est, un cuit quelque peu inflexible déléguer la méthode.

Peut-être ont-ils rencontré des tas de mauvais code de la part de personnes ne comprenant pas vraiment comment cela est mis en place, d'où leur prudence.

Mais bien sûr, si tout ce que vous avez à faire est de rejeter la chose, allez-y.

Ma propre approche est un compromis, au moins cela me rappelle ce qui se passe:

  [[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

[Rapide]

  self.presentingViewController?.dismiss(animated: false, completion:nil)

26
Il convient de noter que l'utilisation presentingViewControllerest la plupart du temps inutile car elle se réfère au UINavigationControllerif selfest intégré dans un. Dans ce cas, vous ne pourrez pas du tout obtenir le presentingViewController. Pourtant, [self dismissViewControllerAnimated:completion]fonctionne toujours dans ce cas. Ma suggestion serait de continuer à l'utiliser jusqu'à ce qu'Apple le corrige.
memmons

4
J'adore que cette réponse soit toujours totalement pertinente 3 ans plus tard.
user1021430

1
Une autre chose à considérer est qu'un contrôleur de vue ne sait pas comment il a été affiché. Il peut avoir été présenté, poussé sur un contrôleur de navigation, une partie d'un contrôleur de barre d'onglets, etc. L'utilisation du délégué permet au contrôleur de vue "présentant" de "rejeter" le contrôleur de vue en utilisant l'inverse de la méthode utilisée pour le présenter.
David Smith

51

Mis à jour pour Swift 3

Je suis venu ici simplement pour supprimer le contrôleur de vue actuel (présenté). Je fais cette réponse pour quiconque vient ici avec le même objectif.

Contrôleur de navigation

Si vous utilisez un contrôleur de navigation, c'est assez simple.

Revenez au contrôleur de vue précédent:

// Swift
self.navigationController?.popViewController(animated: true)

// Objective-C
[self.navigationController popViewControllerAnimated:YES];

Revenez au contrôleur de vue racine:

// Swift
self.navigationController?.popToRootViewController(animated: true)

// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];

(Merci à cette réponse pour l'Objective-C.)

Contrôleur de vue modale

Lorsqu'un contrôleur de vue est présenté de manière modale, vous pouvez le rejeter (à partir du deuxième contrôleur de vue) en appelant

// Swift
self.dismiss(animated: true, completion: nil)

// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];

La documentation dit,

Le contrôleur de vue de présentation est responsable de la suppression du contrôleur de vue qu'il a présenté. Si vous appelez cette méthode sur le contrôleur de vue présenté lui-même, UIKit demande au contrôleur de vue de présentation de gérer le rejet.

Cela fonctionne donc pour le contrôleur de vue présenté de l'appeler sur lui-même. Voici un exemple complet.

Délégués

La question du PO portait sur la complexité de l'utilisation de délégués pour rejeter une vue.

À ce stade, je n'ai pas eu besoin d'utiliser de délégués car j'ai généralement un contrôleur de navigation ou des contrôleurs de vue modale, mais si je dois utiliser le modèle de délégué à l'avenir, j'ajouterai une mise à jour.


50

Ceci est pour la réutilisabilité du contrôleur de vue.

Votre contrôleur de vue ne devrait pas se soucier s'il est présenté comme un modal, poussé sur un contrôleur de navigation ou autre. Si votre contrôleur de vue se ferme, vous supposez qu'il est présenté de manière modale. Vous ne pourrez pas pousser ce contrôleur de vue sur un contrôleur de navigation.

En implémentant un protocole, vous laissez le contrôleur de vue parent décider de la manière dont il doit être présenté / poussé et rejeté / poppé.



6

D'après mon expérience, il est utile lorsque vous devez l'éliminer de tout supprimer ViewController de votre choix et effectuer différentes tâches pour chaque viewcontroller qui le rejette. Tout viewController qui adopte le protocole peut rejeter la vue à sa manière. (ipad vs iphone, ou transmission de données différentes lors du rejet de différentes vues, appel de différentes méthodes lors du rejet, etc.)

Éditer:

Donc, pour clarifier, si tout ce que vous voulez faire est de fermer la vue, je ne vois pas la nécessité de configurer le protocole de délégué. Si vous avez besoin de faire différentes choses après l'avoir écarté de différents contrôleurs de vue de présentation, ce serait votre meilleure façon d'utiliser le délégué.


mais si je n'ai pas besoin de "passer des données différentes lors du rejet de différentes vues, d'appeler différentes méthodes lors du rejet, etc." puis-je faire un petit appel dans la méthode de contrôleur de vue présentée - [self ignoreViewControllerAnimated: AUCUN achèvement: nil]?
nikitahils

Laisser le présentateur rejeter la vue présentée montre clairement que le présentateur est en fait prêt et gère le retour au premier plan: la séquence d'exécution est facile à suivre et la responsabilité de toute mise à jour de l'interface utilisateur est implicitement claire.
Johan

2

Citation du Guide de programmation de View Controller , "Comment les contrôleurs de vue présentent d'autres contrôleurs de vue".

Chaque contrôleur de vue dans une chaîne de contrôleurs de vue présentés a des pointeurs vers les autres objets qui l'entourent dans la chaîne. En d'autres termes, un contrôleur de vue présenté qui présente un autre contrôleur de vue a des objets valides dans ses propriétés PresentViewController et PresentViewController. Vous pouvez utiliser ces relations pour suivre la chaîne de contrôleurs de vue selon vos besoins. Par exemple, si l'utilisateur annule l'opération en cours, vous pouvez supprimer tous les objets de la chaîne en supprimant le premier contrôleur de vue présenté. La suppression d'un contrôleur de vue supprime non seulement ce contrôleur de vue, mais également tous les contrôleurs de vue qu'il a présentés.

Donc d'un côté ça fait un joli design équilibré, un bon découplage, etc ... Mais d'un autre côté c'est très pratique, car on peut rapidement revenir à un certain point de la navigation.

Bien que, personnellement, je préfère utiliser le déroulement des segues plutôt que d'essayer de parcourir en arrière l' arborescence des contrôleurs de vue de présentation , ce dont Apple parle dans ce chapitre d'où provient la citation.


2

Un point est que c'est une bonne approche de codage. Il satisfait à de nombreux OOPprincipes, par exemple, SRP, séparation des préoccupations, etc.

Ainsi, le contrôleur de vue présentant la vue doit être celui qui la rejette.

Par exemple, une société immobilière qui donne une maison à louer devrait être habilitée à la reprendre.


2

Swift 3.0 // Ignorer le contrôleur de vue dans Swift

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)

1

En plus de la réponse de Michael Enriquez, je peux penser à une autre raison pour laquelle cela peut être un bon moyen de se protéger d'un état indéterminé:

Dites que ViewControllerA présente ViewControllerB de manière modale. Mais comme vous n'avez peut-être pas écrit le code de ViewControllerA, vous n'êtes pas conscient du cycle de vie de ViewControllerA. Il peut ignorer 5 secondes (par exemple) après avoir présenté votre contrôleur de vue, ViewControllerB.

Dans ce cas, si vous utilisiez simplement dismissViewController de ViewControllerB pour se fermer, vous vous retrouveriez dans un état indéfini - peut-être pas un crash ou un écran noir mais un état non défini de votre point de vue.

Si, à la place, vous utilisiez le modèle de délégué, vous seriez au courant de l'état de ViewControllerB et vous pouvez programmer pour un cas comme celui que j'ai décrit.


1

Rapide

let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }

0

Si vous utilisez la vue d'utilisation modale, ignorez.

[self dismissViewControllerAnimated:NO completion:nil];

Comment cela répond-il à la question: "Pourquoi le premier choix est-il meilleur? Pourquoi Apple le recommande-t-il?"
jww

0

C'est beaucoup de bêtises. La délégation est bien quand elle est nécessaire, mais si elle rend le code plus complexe - et c'est le cas - alors il doit y avoir une raison à cela.

Je suis sûr qu'Apple a ses raisons. Mais il est plus clair et plus concis de demander simplement au VC présenté de faire le rejet à moins qu'il n'y ait une vraie raison de faire autrement et que personne ici à ce jour n'en ait présenté une que je puisse voir.

Les protocoles sont excellents lorsqu'ils sont nécessaires, mais la conception orientée objet n'a jamais consisté à faire communiquer inutilement des modules entre eux.

Tom Love (co-développeur d'Objective C) a dit un jour qu'Objective C était "élégant", "petit", "net" et "bien défini" (en comparaison avec C ++). Facile à dire pour lui. La délégation est une fonctionnalité utile qui semble avoir été sur-utilisée "juste parce que", et bien que j'aime travailler dans le langage, je redoute l'idée de me sentir obligé d'utiliser une syntaxe inutile pour rendre les choses plus complexes qu'elles ne le devraient.


Cela peut vous faire économiser du code au départ, mais votre approche vous causera de nombreux maux de tête à mesure que votre base de code se développera. Vous devez comprendre les principes orientés objet tels que la séparation des préoccupations, sinon vous pouvez aussi coder l'ensemble de votre application dans un seul gros fichier.
Werner Altewischer

-2

Vous pouvez fermer votre fenêtre Super View

self.view.superview?.window?.close()

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.