Angenommen, ich habe mehrere View Controller in meiner Swift-App und möchte Daten zwischen ihnen übertragen können. Wie übergebe ich Daten an einen anderen View Controller, wenn ich mehrere Ebenen tiefer in einem View Controller-Stapel bin? Oder zwischen Registerkarten in einem Registerkarten-Ansichts-Controller?
(Beachten Sie, dass diese Frage ein "Wecker" ist.) Sie wird so oft gestellt, dass ich beschlossen habe, ein Tutorial zu diesem Thema zu schreiben. Siehe meine Antwort unten.
Antworten:
Ihre Frage ist sehr weit gefasst. Zu behaupten, dass es für jedes Szenario eine einfache Komplettlösung gibt, ist ein wenig naiv. Lassen Sie uns einige dieser Szenarien durchgehen.
Das meiner Erfahrung nach häufigste Szenario für Stapelüberlauf ist die einfache Weitergabe von Informationen von einem Ansichts-Controller zum nächsten.
Wenn wir ein Storyboard verwenden, kann unser erster Ansichts-Controller überschreiben
prepareForSegue
, und genau dafür ist er da.UIStoryboardSegue
Beim Aufruf dieser Methode wird ein Objekt übergeben, das einen Verweis auf unseren Zielansichts-Controller enthält. Hier können wir die Werte festlegen, die wir übergeben möchten.Wenn wir alternativ keine Storyboards verwenden, laden wir unseren View Controller von einer Schreibfeder. Unser Code ist dann etwas einfacher.
In beiden Fällen
myInformation
ist eine Eigenschaft auf jedem Ansichtscontroller enthalten, die alle Daten enthält, die von einem Ansichtscontroller zum nächsten übertragen werden müssen. Sie müssen natürlich nicht auf jedem Controller den gleichen Namen haben.Möglicherweise möchten wir auch Informationen zwischen Registerkarten in a austauschen
UITabBarController
.In diesem Fall ist es möglicherweise sogar noch einfacher.
Lassen Sie uns zunächst eine Unterklasse von erstellen
UITabBarController
und ihr Eigenschaften für alle Informationen zuweisen, die wir zwischen den verschiedenen Registerkarten teilen möchten:Wenn wir jetzt unsere App aus dem Storyboard erstellen, ändern wir einfach die Klasse unseres Tab-Bar-Controllers von der Standardeinstellung
UITabBarController
inMyCustomTabController
. Wenn wir kein Storyboard verwenden, instanziieren wir einfach eine Instanz dieser benutzerdefinierten Klasse anstelle der StandardklasseUITabBarController
und fügen unseren View Controller hinzu.Jetzt können alle unsere Ansichtscontroller in der Registerkartensteuerung auf diese Eigenschaft als solche zugreifen:
Und indem
UINavigationController
wir auf die gleiche Weise Unterklassen erstellen, können wir den gleichen Ansatz verfolgen, um Daten über einen gesamten Navigationsstapel hinweg gemeinsam zu nutzen:Es gibt mehrere andere Szenarien. Diese Antwort deckt keineswegs alle ab.
quelle
prepareForSegue
. Es ist schade, dass diese sehr einfache Beobachtung unter den anderen Antworten und Abweichungen hier verloren geht.prepareForSegue
andere direkte Informationsübertragung bevorzugen oder andere und dann einfach mit den Anfängern einverstanden sein, wenn sie mit dem Szenario auftauchen, für das diese Situationen nicht funktionieren, und wir müssen sie dann über diese globaleren Ansätze unterrichten.Diese Frage taucht ständig auf.
Ein Vorschlag besteht darin, einen Datencontainer-Singleton zu erstellen: Ein Objekt, das einmal und nur einmal im Leben Ihrer Anwendung erstellt wird und für das Leben Ihrer App bestehen bleibt.
Dieser Ansatz eignet sich gut für Situationen, in denen Sie über globale App-Daten verfügen, die für verschiedene Klassen in Ihrer App verfügbar / änderbar sein müssen.
Andere Ansätze wie das Einrichten von Einweg- oder Zweiwegverbindungen zwischen Ansichtssteuerungen eignen sich besser für Situationen, in denen Sie Informationen / Nachrichten direkt zwischen Ansichtssteuerungen weitergeben.
(Weitere Alternativen finden Sie in der Antwort von nhgrif weiter unten.)
Mit einem Datencontainer-Singleton fügen Sie Ihrer Klasse eine Eigenschaft hinzu, in der ein Verweis auf Ihren Singleton gespeichert ist, und verwenden diese Eigenschaft dann, wenn Sie Zugriff benötigen.
Sie können Ihren Singleton so einrichten, dass er seinen Inhalt auf der Festplatte speichert, sodass Ihr App-Status zwischen den Starts bestehen bleibt.
Ich habe auf GitHub ein Demo-Projekt erstellt, das zeigt, wie Sie dies tun können. Hier ist der Link:
SwiftDataContainerSingleton-Projekt auf GitHub Hier ist die README von diesem Projekt:
SwiftDataContainerSingleton
Eine Demonstration der Verwendung eines Datencontainer-Singletons zum Speichern des Anwendungsstatus und zum Freigeben zwischen Objekten.
Die
DataContainerSingleton
Klasse ist der eigentliche Singleton.Es verwendet eine statische Konstante
sharedDataContainer
, um einen Verweis auf den Singleton zu speichern.Verwenden Sie die Syntax, um auf den Singleton zuzugreifen
Das Beispielprojekt definiert 3 Eigenschaften im Datencontainer:
Um die
someInt
Eigenschaft aus dem Datencontainer zu laden , verwenden Sie folgenden Code:Um einen Wert in someInt zu speichern, verwenden Sie die folgende Syntax:
Die DataContainerSingleton-
init
Methode fügt einen Beobachter für die hinzuUIApplicationDidEnterBackgroundNotification
. Dieser Code sieht folgendermaßen aus:Im Beobachtercode werden die Eigenschaften des Datencontainers in gespeichert
NSUserDefaults
. Sie können auchNSCoding
Core Data oder verschiedene andere Methoden zum Speichern von Statusdaten verwenden.Die DataContainerSingleton-
init
Methode versucht auch, gespeicherte Werte für ihre Eigenschaften zu laden.Dieser Teil der init-Methode sieht folgendermaßen aus:
Die Schlüssel zum Laden und Speichern von Werten in NSUserDefaults werden als Zeichenfolgenkonstanten gespeichert, die Teil einer Struktur sind
DefaultsKeys
, die wie folgt definiert ist:Sie verweisen auf eine dieser Konstanten wie folgt:
Verwenden des Datencontainers Singleton:
Diese Beispielanwendung verwendet den Datencontainer-Singleton in drei Fällen.
Es gibt zwei Ansichtssteuerungen. Die erste ist eine benutzerdefinierte Unterklasse von UIViewController
ViewController
und die zweite ist eine benutzerdefinierte Unterklasse von UIViewControllerSecondVC
.Auf beiden Ansichts-Controllern befindet sich ein Textfeld, und beide laden
someInt
in ihrerviewWillAppear
Methode einen Wert aus der Eigenschaft des Datencontainers singlelton in das Textfeld , und beide speichern den aktuellen Wert aus dem Textfeld zurück im `someInt 'des Datencontainers.Der Code zum Laden des Werts in das Textfeld befindet sich in der
viewWillAppear:
Methode:Der Code zum Speichern des vom Benutzer bearbeiteten Werts im Datencontainer befindet sich in den
textFieldShouldEndEditing
Methoden der View Controller :Sie sollten Werte in viewWillAppear und nicht in viewDidLoad in Ihre Benutzeroberfläche laden, damit Ihre Benutzeroberfläche jedes Mal aktualisiert wird, wenn der View Controller angezeigt wird.
quelle
Swift 4
Es gibt so viele Ansätze für die schnelle Datenübertragung. Hier füge ich einige der besten Ansätze hinzu.
1) Verwenden von StoryBoard Segue
Storyboard-Segmente sind sehr nützlich, um Daten zwischen Quell- und Zielansichts-Controllern zu übertragen und umgekehrt.
2) Verwenden von Delegate-Methoden
ViewControllerD
ViewControllerC
quelle
ViewControllerA
nach verwendetViewControllerB
. Ich habe gerade das Code-Snippet unten in meineViewControllerA.swift
(woViewControllerA.swift
ist eigentlich was auch immer Ihre Datei heißt, natürlich) kurz vor der letzten geschweiften Klammer geklebt . "prepare
" ist eigentlich eine spezielle eingebaute vorbestehende Funktion in einer bestimmten Klasse [die nichts tut], weshalb Sie es "override
" müssenEine andere Alternative besteht darin, das Benachrichtigungscenter (NSNotificationCenter) zu verwenden und Benachrichtigungen zu veröffentlichen. Das ist eine sehr lockere Kupplung. Der Absender einer Benachrichtigung muss nicht wissen oder sich darum kümmern, wer zuhört. Es sendet nur eine Benachrichtigung und vergisst sie.
Benachrichtigungen eignen sich für die Weitergabe von Eins-zu-Viele-Nachrichten, da eine beliebige Anzahl von Beobachtern auf eine bestimmte Nachricht warten kann.
quelle
Anstatt ein Datencontroller-Singelton zu erstellen, würde ich vorschlagen, eine Datencontroller-Instanz zu erstellen und weiterzugeben. Um die Abhängigkeitsinjektion zu unterstützen, würde ich zuerst ein
DataController
Protokoll erstellen :Dann würde ich eine
SpecificDataController
Klasse (oder einen anderen Namen, der derzeit angemessen wäre) erstellen :Die
ViewController
Klasse sollte dann ein Feld haben, um das zu haltendataController
. Beachten Sie, dass der TypdataController
das Protokoll istDataController
. Auf diese Weise ist es einfach, Datencontroller-Implementierungen auszutauschen:In können
AppDelegate
wir den viewController einstellendataController
:Wenn wir zu einem anderen viewController wechseln, können wir Folgendes weitergeben
dataController
:Wenn wir nun den Datencontroller für eine andere Aufgabe ausschalten möchten, können wir dies im
AppDelegate
und müssen keinen anderen Code ändern, der den Datencontroller verwendet.Dies ist natürlich übertrieben, wenn wir einfach einen einzelnen Wert weitergeben möchten. In diesem Fall ist es am besten, mit der Antwort von nhgrif zu gehen.
Mit diesem Ansatz können wir die Ansicht vom logischen Teil trennen.
quelle
Wie @nhgrif in seiner hervorragenden Antwort hervorhob, gibt es viele verschiedene Möglichkeiten, wie VCs (View Controller) und andere Objekte miteinander kommunizieren können.
Bei dem in meiner ersten Antwort skizzierten Daten-Singleton geht es mehr um das Teilen und Speichern des globalen Status als um die direkte Kommunikation.
Mit der Antwort von nhrif können Sie Informationen direkt von der Quelle an die Ziel-VC senden. Wie ich in der Antwort erwähnt habe, ist es auch möglich, Nachrichten vom Ziel an die Quelle zurückzusenden.
Tatsächlich können Sie einen aktiven Einweg- oder Zweiwegkanal zwischen verschiedenen Ansichtssteuerungen einrichten. Wenn die Ansichtscontroller über einen Storyboard-Übergang verknüpft sind, liegt die Zeit zum Einrichten der Verknüpfungen in der prepareFor Segue-Methode.
Ich habe ein Beispielprojekt auf Github, das einen übergeordneten Ansichts-Controller verwendet, um zwei verschiedene Tabellenansichten als untergeordnete Elemente zu hosten. Die untergeordneten Ansichtscontroller werden mithilfe von Einbettungssegmenten verknüpft, und der übergeordnete Ansichtscontroller verbindet in der prepareForSegue-Methode bidirektionale Verknüpfungen mit jedem Ansichtscontroller.
Sie finden das Projekt auf github (Link). Ich habe es jedoch in Objective-C geschrieben und es nicht in Swift konvertiert. Wenn Sie sich in Objective-C nicht wohl fühlen, ist es möglicherweise etwas schwierig, dem zu folgen
quelle
SWIFT 3:
Wenn Sie ein Storyboard mit identifizierten Abschnitten haben, verwenden Sie:
Wenn Sie jedoch alles programmgesteuert ausführen, einschließlich der Navigation zwischen verschiedenen UIViewControllern, verwenden Sie die folgende Methode:
Hinweis: Um die zweite Methode zu verwenden, mit der Sie Ihren UINavigationController erstellen müssen, müssen Sie UIViewController als Delegierten aktivieren und es muss dem Protokoll UINavigationControllerDelegate entsprechen:
quelle
Dies hängt davon ab, wann Sie Daten abrufen möchten.
Wenn Sie Daten abrufen möchten, wann immer Sie möchten, können Sie ein Singleton-Muster verwenden. Die Musterklasse ist während der App-Laufzeit aktiv. Hier ist ein Beispiel für das Singleton-Muster.
Wenn Sie nach einer Aktion Daten abrufen möchten, können Sie NotificationCenter verwenden.
quelle