Verwerfen eines Presented View Controllers

116

Ich habe eine theoretische Frage. Jetzt lese ich Apples ViewController- Handbuch.

Sie schrieben:

Wenn es an der Zeit ist, einen Controller für präsentierte Ansichten zu schließen, besteht der bevorzugte Ansatz darin, den Controller für präsentierte Ansichten entlassen zu lassen. Mit anderen Worten, wann immer möglich, sollte derselbe Ansichtscontroller, der den Ansichtscontroller vorgestellt hat, auch die Verantwortung für die Entlassung übernehmen. Obwohl es verschiedene Techniken gibt, um den Controller für die präsentierende Ansicht zu benachrichtigen, dass sein Controller für die präsentierte Ansicht entlassen werden sollte, ist die Delegierung die bevorzugte Technik.

Aber ich kann nicht erklären, warum ich ein Protokoll in der präsentierten VC erstellen und eine delegierte Variable hinzufügen muss, eine Delegatenmethode in der präsentierten VC erstellen muss, um die präsentierte VC zu schließen, anstatt einen einfachen Aufruf in der präsentierten View-Controller-Methode

[self dismissViewControllerAnimated:NO completion:nil]?

Warum ist die erste Wahl besser? Warum empfiehlt Apple es?

Nikitahils
quelle

Antworten:

121

Ich denke, Apple deckt hier ein wenig den Rücken für ein möglicherweise klobiges Stück API.

  [self dismissViewControllerAnimated:NO completion:nil]

Ist eigentlich ein bisschen eine Geige. Obwohl Sie dies zu Recht auf dem präsentierten Ansichts-Controller aufrufen können, wird die Nachricht lediglich an den präsentierenden Ansichts-Controller weitergeleitet. Wenn Sie etwas anderes tun möchten, als nur den VC zu entlassen, müssen Sie dies wissen und es genauso behandeln wie eine Delegatenmethode - da es so ziemlich das ist, was es ist, eine eingebrannte, etwas unflexible Methode delegieren.

Vielleicht sind sie auf eine Menge schlechten Codes gestoßen, weil die Leute nicht wirklich verstanden haben, wie dies zusammengesetzt ist, daher ihre Vorsicht.

Aber wenn Sie das Ding nur ablehnen müssen, fahren Sie fort.

Mein eigener Ansatz ist ein Kompromiss, zumindest erinnert er mich daran, was los ist:

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

[Schnell]

  self.presentingViewController?.dismiss(animated: false, completion:nil)
Gießerei
quelle
26
Es sollte beachtet werden, dass die Verwendung presentingViewControllermeistens nutzlos ist, da sie sich auf das in eins eingebettete UINavigationControllerif bezieht self. In diesem Fall können Sie das überhaupt nicht bekommen presentingViewController. Funktioniert [self dismissViewControllerAnimated:completion]in diesem Fall jedoch immer noch. Mein Vorschlag wäre, das weiterhin zu verwenden, bis Apple es behebt.
Memmons
4
Ich finde es toll, dass diese Antwort auch 3 Jahre später noch absolut relevant ist.
user1021430
1
Zu beachten ist außerdem, dass ein View Controller nicht weiß, wie er angezeigt wurde. Es wurde möglicherweise präsentiert, auf einen Navigationscontroller, einen Teil eines Registerkartenleisten-Controllers usw. verschoben. Durch die Verwendung des Delegaten kann der Ansichts-Controller "Präsentieren" den Ansichts-Controller mit der Umkehrung der Methode, mit der er präsentiert wurde, "schließen".
David Smith
51

Aktualisiert für Swift 3

Ich bin hierher gekommen, um den aktuellen (vorgestellten) View Controller zu schließen. Ich mache diese Antwort für jeden, der mit dem gleichen Ziel hierher kommt.

Navigationssteuerung

Wenn Sie einen Navigationscontroller verwenden, ist dies recht einfach.

Kehren Sie zum vorherigen Ansichts-Controller zurück:

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

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

Gehen Sie zurück zum Root View Controller:

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

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

(Dank dieser Antwort für das Ziel-C.)

Modal View Controller

Wenn ein View Controller modal dargestellt wird, können Sie ihn (vom zweiten View Controller) durch Aufrufen schließen

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

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

Die Dokumentation sagt,

Der präsentierende View Controller ist dafür verantwortlich, den präsentierten View Controller zu schließen. Wenn Sie diese Methode auf dem präsentierten Ansichtscontroller selbst aufrufen, fordert UIKit den präsentierenden Ansichtscontroller auf, die Entlassung zu behandeln.

Es funktioniert also, wenn der vorgestellte View Controller es selbst aufruft. Hier ist ein vollständiges Beispiel.

Delegierte

Die Frage des OP betraf die Komplexität der Verwendung von Delegierten zum Ablehnen einer Ansicht.

Bis jetzt musste ich keine Delegaten verwenden, da ich normalerweise einen Navigationscontroller oder Modal View Controller habe. Wenn ich jedoch in Zukunft das Delegatenmuster verwenden muss , werde ich ein Update hinzufügen.

Suragch
quelle
50

Dies dient der Wiederverwendbarkeit des View Controllers.

Ihr View Controller sollte sich nicht darum kümmern, ob er als Modal, auf einem Navigationscontroller oder was auch immer dargestellt wird. Wenn sich Ihr View Controller selbst schließt, gehen Sie davon aus, dass er modal dargestellt wird. Sie können diesen Ansichts-Controller nicht auf einen Navigations-Controller übertragen.

Durch die Implementierung eines Protokolls lassen Sie den übergeordneten Ansichtscontroller entscheiden, wie es präsentiert / gepusht und entlassen / gepoppt werden soll.

Michael Enriquez
quelle
7

Versuche dies:

[self dismissViewControllerAnimated:true completion:nil];
Oshitha Wimalasuriya
quelle
6

Nach meiner Erfahrung ist es praktisch, wenn Sie es von einem beliebigen ViewController entfernen und für jeden Viewcontroller, der es entlässt, unterschiedliche Aufgaben ausführen müssen. Jeder viewController, der das Protokoll übernimmt, kann die Ansicht auf seine eigene Weise schließen. (ipad vs iphone oder Übergabe unterschiedlicher Daten beim Verlassen aus verschiedenen Ansichten, Aufrufen verschiedener Methoden beim Entlassen usw.)

Bearbeiten:

Um zu verdeutlichen, dass Sie das Delegate-Protokoll nicht einrichten müssen, wenn Sie die Ansicht nur schließen möchten. Wenn Sie verschiedene Dinge tun müssen, nachdem Sie sie von verschiedenen Präsentations-View-Controllern entfernt haben, ist dies der beste Weg, um den Delegaten zu verwenden.

jhilgert00
quelle
Aber wenn ich nicht "unterschiedliche Daten übergeben muss, wenn ich aus verschiedenen Ansichten entlassen werde, verschiedene Methoden aufrufen muss, wenn ich entlasse usw.", kann ich dann einen kleinen Aufruf in der dargestellten View-Controller-Methode ausführen - [self EntlassungViewControllerAnimated: NO Vervollständigung: Null]?
Nikitahils
Wenn der Präsentator die präsentierte Ansicht schließen lässt, wird deutlich, dass der Präsentator tatsächlich bereit ist und die Rückkehr in den Vordergrund übernimmt: Die Ausführungsreihenfolge ist einfach zu befolgen, und die Verantwortung für Aktualisierungen der Benutzeroberfläche ist implizit klar.
Johan
2

Zitat aus dem View Controller-Programmierhandbuch , "Wie View Controller andere View Controller darstellen".

Jeder Ansichtscontroller in einer Kette von dargestellten Ansichtscontrollern verfügt über Zeiger auf die anderen ihn umgebenden Objekte in der Kette. Mit anderen Worten, ein präsentierter Ansichtscontroller, der einen anderen Ansichtscontroller präsentiert, hat gültige Objekte sowohl in seinen präsentierendenViewController- als auch präsentiertenViewController-Eigenschaften. Sie können diese Beziehungen verwenden, um die Kette der Ansichtssteuerungen nach Bedarf zu verfolgen. Wenn der Benutzer beispielsweise den aktuellen Vorgang abbricht, können Sie alle Objekte in der Kette entfernen, indem Sie den ersten dargestellten Ansichts-Controller schließen. Durch das Ablehnen eines Ansichtscontrollers werden nicht nur dieser Ansichtscontroller, sondern auch alle von ihm präsentierten Ansichtscontroller geschlossen.

Einerseits sorgt es für ein ausgewogenes Design, eine gute Entkopplung usw. Andererseits ist es sehr praktisch, da Sie schnell zu einem bestimmten Punkt in der Navigation zurückkehren können.

Obwohl ich persönlich lieber Abwicklungsabschnitte verwenden würde, als zu versuchen, den präsentierenden View-Controller- Baum rückwärts zu durchlaufen , worüber Apple in diesem Kapitel spricht, aus dem das Zitat stammt.

Svena
quelle
2

Ein Punkt ist, dass dies ein guter Codierungsansatz ist. Es erfüllt viele OOPPrinzipien, z. B. SRP, Trennung von Bedenken usw.

Daher sollte der Ansichts-Controller, der die Ansicht präsentiert, derjenige sein, der sie ablehnt.

Wie ein Immobilienunternehmen, das ein Haus zur Miete gibt, sollte die Autorität sein, es zurückzunehmen.

Abdurrahman Mubeen Ali
quelle
2

Swift 3.0 // View Controller in Kürze schließen

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

Neben der Antwort von Michael Enriquez kann ich mir einen weiteren Grund vorstellen, warum dies ein guter Weg ist, sich vor einem unbestimmten Zustand zu schützen:

Angenommen, ViewControllerA präsentiert ViewControllerB modal. Da Sie den Code für ViewControllerA möglicherweise nicht geschrieben haben, ist Ihnen der Lebenszyklus von ViewControllerA nicht bekannt. Es kann 5 Sekunden (sagen wir) nach der Präsentation Ihres View Controllers ViewControllerB geschlossen werden.

In diesem Fall würden Sie, wenn Sie einfach dismissViewControllerViewControllerB verwenden, um sich selbst zu schließen, in einen undefinierten Zustand geraten - möglicherweise nicht in einen Absturz oder einen schwarzen Bildschirm, sondern aus Ihrer Sicht in einen undefinierten Zustand.

Wenn Sie stattdessen das Delegatenmuster verwenden, kennen Sie den Status von ViewControllerB und können für einen Fall wie den von mir beschriebenen programmieren.

Mayur
quelle
1

Schnell

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

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

Wenn Sie die modale Verwendung verwenden, schließen Sie die Ansicht.

[self dismissViewControllerAnimated:NO completion:nil];
ErasmoOliveira
quelle
Wie beantwortet dies die Frage: "Warum ist die erste Wahl besser? Warum empfiehlt Apple sie?"
Jww
0

Das ist viel Quatsch. Die Delegierung ist in Ordnung, wenn sie benötigt wird, aber wenn sie den Code komplexer macht - und das tut sie -, muss es einen Grund dafür geben.

Ich bin sicher, Apple hat seine Gründe. Es ist jedoch klarer und prägnanter, den vorgestellten VC einfach die Entlassung vornehmen zu lassen, es sei denn, es gibt einen wahren Grund, etwas anderes zu tun, und niemand hier hat bis heute einen vorgelegt, den ich sehen kann.

Protokolle sind hervorragend, wenn sie benötigt werden, aber beim objektorientierten Design ging es nie darum, dass Module unnötig miteinander kommunizieren.

Tom Love (Mitentwickler von Objective C) bemerkte einmal, dass Objective C "elegant", "klein", "knackig" und "gut definiert" sei (im Vergleich zu C ++). Leicht für ihn zu sagen. Delegation ist eine nützliche Funktion, die "nur weil" überstrapaziert zu sein scheint, und während ich gerne in der Sprache arbeite, fürchte ich die Idee, gezwungen zu sein, unnötige Syntax zu verwenden, um die Dinge komplexer zu machen, als sie sein müssen.

Regulären Ausdruck
quelle
Es kann sein, dass Sie anfangs etwas Code sparen, aber Ihr Ansatz verursacht Ihnen viele Kopfschmerzen, wenn Ihre Codebasis wächst. Sie sollten objektorientierte Prinzipien wie die Trennung von Bedenken verstehen, andernfalls können Sie Ihre gesamte Anwendung genauso gut in einer großen Datei codieren.
Werner Altewischer
-2

Sie können Ihr Super-Ansichtsfenster schließen

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

MR.Code
quelle