Wie können Sie Daten zwischen View Controllern und anderen Objekten in Swift austauschen?

88

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.

Duncan C.
quelle
1
Versuchen Sie, für Delegierte zu googeln
milo526
4
Ich habe dies gepostet, damit ich eine Lösung für die 10.000 Instanzen dieser Frage finden kann, die hier auf SO jeden Tag auftauchen. Siehe meine Selbstantwort. :)
Duncan C
Entschuldigung, ich war zu schnell mit der Reaktion :) gut, um darauf verlinken zu können :)
milo526
2
Keine Sorge. Sie dachten, ich wäre # 10.001, nicht wahr? <grin>
Duncan C
4
@ DuncanC Ich mag deine Antwort nicht. :( Es ist in Ordnung , ist nicht die Antwort auf jedes Szenario ... insomuchas, es wird für jedes Szenario funktionieren , aber es ist auch nicht der richtige Ansatz für fast jedes Szenario. Trotzdem haben wir es jetzt im Kopf dass es eine gute Idee ist, eine Frage zu diesem Thema als Duplikat zu markieren? Bitte nicht.
nhgrif

Antworten:

91

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. UIStoryboardSegueBeim 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.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "MySegueID" {
        if let destination = segue.destination as? SecondController {
            destination.myInformation = self.myInformation
        }
    }
}

Wenn wir alternativ keine Storyboards verwenden, laden wir unseren View Controller von einer Schreibfeder. Unser Code ist dann etwas einfacher.

func showNextController() {
    let destination = SecondController(nibName: "SecondController", bundle: nil)
    destination.myInformation = self.myInformation
    show(destination, sender: self)
}

In beiden Fällen myInformationist 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 UITabBarControllerund ihr Eigenschaften für alle Informationen zuweisen, die wir zwischen den verschiedenen Registerkarten teilen möchten:

class MyCustomTabController: UITabBarController {
    var myInformation: [String: AnyObject]?
}

Wenn wir jetzt unsere App aus dem Storyboard erstellen, ändern wir einfach die Klasse unseres Tab-Bar-Controllers von der Standardeinstellung UITabBarControllerin MyCustomTabController. Wenn wir kein Storyboard verwenden, instanziieren wir einfach eine Instanz dieser benutzerdefinierten Klasse anstelle der Standardklasse UITabBarControllerund fügen unseren View Controller hinzu.

Jetzt können alle unsere Ansichtscontroller in der Registerkartensteuerung auf diese Eigenschaft als solche zugreifen:

if let tbc = self.tabBarController as? MyCustomTabController {
    // do something with tbc.myInformation
}

Und indem UINavigationControllerwir auf die gleiche Weise Unterklassen erstellen, können wir den gleichen Ansatz verfolgen, um Daten über einen gesamten Navigationsstapel hinweg gemeinsam zu nutzen:

if let nc = self.navigationController as? MyCustomNavController {
    // do something with nc.myInformation
}

Es gibt mehrere andere Szenarien. Diese Antwort deckt keineswegs alle ab.

nhgrif
quelle
1
Ich möchte auch hinzufügen, dass manchmal ein Kanal Informationen vom Zielansichts-Controller an den Quellansichts-Controller zurücksenden soll. Eine übliche Methode, um mit dieser Situation umzugehen, besteht darin, dem Ziel eine Delegate-Eigenschaft hinzuzufügen und dann in prepareForSegue des Quellansichts-Controllers die Delegate-Eigenschaft des Zielansichts-Controllers auf self zu setzen. (und definieren Sie ein Protokoll, das die Nachrichten definiert, die der Ziel-VC verwendet, um Nachrichten an den Quell-VC zu senden)
Duncan C
1
nhgrif, ich stimme zu. Der Rat an neue Entwickler sollte lauten: Wenn Sie Daten zwischen Szenen im Storyboard übertragen müssen, verwenden Sie prepareForSegue. Es ist schade, dass diese sehr einfache Beobachtung unter den anderen Antworten und Abweichungen hier verloren geht.
Rob
2
@ Rob Yup. Singletons und Benachrichtigungen sollten die letzte Wahl sein. Wir sollten in fast jedem Szenario eine prepareForSegueandere 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.
nhgrif
1
Es hängt davon ab, ob. Aber ich bin sehr, sehr besorgt darüber, den App-Delegaten als Abladeplatz für Code zu verwenden, von dem wir nicht wissen, wo wir ihn sonst platzieren sollen. Hier liegt der Weg zum Wahnsinn.
nhgrif
2
@nhgrif. Danke für deine Antwort. Was ist, wenn Sie jedoch möchten, dass die Daten zwischen beispielsweise 4 oder 5 Viewcontrollern übertragen werden? Wenn ich sagen muss, dass 4-5 Viewcontroller die Client-Anmeldung und das Passwort usw. verwalten und ich die E-Mail des Benutzers zwischen diesen Viewcontrollern weitergeben möchte, gibt es eine bequemere Möglichkeit, dies zu tun, als die Variable in jedem Viewcontroller zu deklarieren und sie dann in prepareforsegue zu übergeben. Gibt es eine Möglichkeit, die ich einmal deklarieren kann und auf die jeder Viewcontroller zugreifen kann, aber auf eine Weise, die auch eine gute Codierungspraxis ist?
Lozflan
45

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 DataContainerSingletonKlasse 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

DataContainerSingleton.sharedDataContainer

Das Beispielprojekt definiert 3 Eigenschaften im Datencontainer:

  var someString: String?
  var someOtherString: String?
  var someInt: Int?

Um die someIntEigenschaft aus dem Datencontainer zu laden , verwenden Sie folgenden Code:

let theInt = DataContainerSingleton.sharedDataContainer.someInt

Um einen Wert in someInt zu speichern, verwenden Sie die folgende Syntax:

DataContainerSingleton.sharedDataContainer.someInt = 3

Die DataContainerSingleton- initMethode fügt einen Beobachter für die hinzu UIApplicationDidEnterBackgroundNotification. Dieser Code sieht folgendermaßen aus:

goToBackgroundObserver = NSNotificationCenter.defaultCenter().addObserverForName(
  UIApplicationDidEnterBackgroundNotification,
  object: nil,
  queue: nil)
  {
    (note: NSNotification!) -> Void in
    let defaults = NSUserDefaults.standardUserDefaults()
    //-----------------------------------------------------------------------------
    //This code saves the singleton's properties to NSUserDefaults.
    //edit this code to save your custom properties
    defaults.setObject( self.someString, forKey: DefaultsKeys.someString)
    defaults.setObject( self.someOtherString, forKey: DefaultsKeys.someOtherString)
    defaults.setObject( self.someInt, forKey: DefaultsKeys.someInt)
    //-----------------------------------------------------------------------------

    //Tell NSUserDefaults to save to disk now.
    defaults.synchronize()
}

Im Beobachtercode werden die Eigenschaften des Datencontainers in gespeichert NSUserDefaults. Sie können auch NSCodingCore Data oder verschiedene andere Methoden zum Speichern von Statusdaten verwenden.

Die DataContainerSingleton- initMethode versucht auch, gespeicherte Werte für ihre Eigenschaften zu laden.

Dieser Teil der init-Methode sieht folgendermaßen aus:

let defaults = NSUserDefaults.standardUserDefaults()
//-----------------------------------------------------------------------------
//This code reads the singleton's properties from NSUserDefaults.
//edit this code to load your custom properties
someString = defaults.objectForKey(DefaultsKeys.someString) as! String?
someOtherString = defaults.objectForKey(DefaultsKeys.someOtherString) as! String?
someInt = defaults.objectForKey(DefaultsKeys.someInt) as! Int?
//-----------------------------------------------------------------------------

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:

struct DefaultsKeys
{
  static let someString  = "someString"
  static let someOtherString  = "someOtherString"
  static let someInt  = "someInt"
}

Sie verweisen auf eine dieser Konstanten wie folgt:

DefaultsKeys.someInt

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 ViewControllerund die zweite ist eine benutzerdefinierte Unterklasse von UIViewController SecondVC.

Auf beiden Ansichts-Controllern befindet sich ein Textfeld, und beide laden someIntin ihrer viewWillAppearMethode 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:

override func viewWillAppear(animated: Bool)
{
  //Load the value "someInt" from our shared ata container singleton
  let value = DataContainerSingleton.sharedDataContainer.someInt ?? 0
  
  //Install the value into the text field.
  textField.text =  "\(value)"
}

Der Code zum Speichern des vom Benutzer bearbeiteten Werts im Datencontainer befindet sich in den textFieldShouldEndEditingMethoden der View Controller :

 func textFieldShouldEndEditing(textField: UITextField) -> Bool
 {
   //Save the changed value back to our data container singleton
   DataContainerSingleton.sharedDataContainer.someInt = textField.text!.toInt()
   return true
 }

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.

Duncan C.
quelle
8
Ich möchte dies nicht ablehnen, weil ich es hervorragend finde, dass Sie die Zeit investiert haben, um die Frage und Antwort als Ressource zu erstellen. Danke dir. Ungeachtet dessen denke ich, dass wir neuen Entwicklern einen großen Nachteil erweisen, Singletons für Modellobjekte zu befürworten. Ich bin nicht im Lager "Singletons sind böse" (obwohl Noobs diesen Satz googeln sollten, um die Probleme besser zu verstehen), aber ich denke, Modelldaten sind eine fragwürdige / umstrittene Verwendung von Singletons.
Rob
Ich
@Duncan C Hallo Duncan, ich mache in jedem Modell ein statisches Objekt, damit ich Daten von jedem Ort bekomme, an dem es richtig ist, oder ich muss deinem Pfad folgen, weil es sehr richtig erscheint.
Virendra Singh Rathore
@VirendraSinghRathore, Globale statische Variablen sind die schlechteste Möglichkeit, Daten in der App gemeinsam zu nutzen. Sie koppeln die Teile Ihrer App eng miteinander und führen zu schwerwiegenden Abhängigkeiten. Es ist das genaue Gegenteil von "sehr richtig".
Duncan C
@DuncanC - würde dieses Muster für ein CurrentUser-Objekt funktionieren - im Grunde genommen für einen einzelnen Benutzer, der bei Ihrer App angemeldet ist? thx
timpone
9

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.

// If you want to pass data from ViewControllerB to ViewControllerA while user tap on back button of ViewControllerB.
        @IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
            if sender.source is ViewControllerB  {
                if let _ = sender.source as? ViewControllerB {
                    self.textLabel.text = "Came from B = B->A , B exited"
                }
            }
        }

// If you want to send data from ViewControllerA to ViewControllerB
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if  segue.destination is ViewControllerB {
                if let vc = segue.destination as? ViewControllerB {
                    vc.dataStr = "Comming from A View Controller"
                }
            }
        }

2) Verwenden von Delegate-Methoden

ViewControllerD

//Make the Delegate protocol in Child View Controller (Make the protocol in Class from You want to Send Data)
    protocol  SendDataFromDelegate {
        func sendData(data : String)
    }

    import UIKit

    class ViewControllerD: UIViewController {

        @IBOutlet weak var textLabelD: UILabel!

        var delegate : SendDataFromDelegate?  //Create Delegate Variable for Registering it to pass the data

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            textLabelD.text = "Child View Controller"
        }

        @IBAction func btnDismissTapped (_ sender : UIButton) {
            textLabelD.text = "Data Sent Successfully to View Controller C using Delegate Approach"
            self.delegate?.sendData(data:textLabelD.text! )
            _ = self.dismiss(animated: true, completion:nil)
        }
    }

ViewControllerC

    import UIKit

    class ViewControllerC: UIViewController , SendDataFromDelegate {

        @IBOutlet weak var textLabelC: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }

        @IBAction func btnPushToViewControllerDTapped( _ sender : UIButton) {
            if let vcD = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerD") as?  ViewControllerD  {
                vcD.delegate = self // Registring Delegate (When View Conteoller D gets Dismiss It can call sendData method
    //            vcD.textLabelD.text = "This is Data Passing by Referenceing View Controller D Text Label." //Data Passing Between View Controllers using Data Passing
                self.present(vcD, animated: true, completion: nil)
            }
        }

        //This Method will called when when viewcontrollerD will dismiss. (You can also say it is a implementation of Protocol Method)
        func sendData(data: String) {
            self.textLabelC.text = data
        }

    }
iOS-Team
quelle
Für Googler, die so völlig und völlig verloren sind, wo sie die Swift-Code-Schnipsel von StackOverflow-Antworten ablegen sollen, wie ich es bin, sollten Sie immer wissen, wohin sie den Code leiten: Ich habe Option 1) zum Senden von ViewControllerAnach verwendet ViewControllerB. Ich habe gerade das Code-Snippet unten in meine ViewControllerA.swift(wo ViewControllerA.swiftist 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üssen
velkoon
8

Eine 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.

Duncan C.
quelle
2
Beachten Sie, dass die Verwendung des Benachrichtigungscenters eine möglicherweise zu lockere Kopplung einführt . Dies kann es sehr schwierig machen, den Ablauf Ihres Programms zu verfolgen. Daher sollte es mit Vorsicht verwendet werden.
Duncan C
2

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 DataControllerProtokoll erstellen :

protocol DataController {
    var someInt : Int {get set} 
    var someString : String {get set}
}

Dann würde ich eine SpecificDataControllerKlasse (oder einen anderen Namen, der derzeit angemessen wäre) erstellen :

class SpecificDataController : DataController {
   var someInt : Int = 5
   var someString : String = "Hello data" 
}

Die ViewControllerKlasse sollte dann ein Feld haben, um das zu halten dataController. Beachten Sie, dass der Typ dataControllerdas Protokoll ist DataController. Auf diese Weise ist es einfach, Datencontroller-Implementierungen auszutauschen:

class ViewController : UIViewController {
   var dataController : DataController?
   ...
}

In können AppDelegatewir den viewController einstellen dataController:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if let viewController = self.window?.rootViewController as? ViewController {
        viewController.dataController =  SpecificDataController()
    }   
    return true
}

Wenn wir zu einem anderen viewController wechseln, können wir Folgendes weitergeben dataController:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    ...   
}

Wenn wir nun den Datencontroller für eine andere Aufgabe ausschalten möchten, können wir dies im AppDelegateund 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.

Kristiina
quelle
1
Hallo, dieser Ansatz ist sauber, testbar und wird meistens in kleinen Anwendungen verwendet, aber in größeren, in denen möglicherweise nicht jeder VC (möglicherweise nicht einmal der Root-VC) die Abhängigkeit benötigt (in diesem Fall z. B. DataController) Es scheint verschwenderisch, wenn jeder VC die Abhängigkeit benötigt, um sie weiterzugeben. Wenn Sie verschiedene Arten von VCs verwenden (z. B. reguläres UIVC oder NavigationVC), müssen Sie diese verschiedenen Typen in Unterklassen unterteilen, um diese Abhängigkeitsvariable hinzuzufügen. Wie nähern Sie sich dem?
RobertoCuba
1

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

Duncan C.
quelle
1

SWIFT 3:

Wenn Sie ein Storyboard mit identifizierten Abschnitten haben, verwenden Sie:

func prepare(for segue: UIStoryboardSegue, sender: Any?)

Wenn Sie jedoch alles programmgesteuert ausführen, einschließlich der Navigation zwischen verschiedenen UIViewControllern, verwenden Sie die folgende Methode:

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)

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:

   class MyNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {

     // do what ever you need before going to the next UIViewController or back
     //this method will be always called when you are pushing or popping the ViewController

    }
}
Maxime
quelle
mach niemals self.delegate = self
malhal
1

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.

class AppSession: NSObject {

    static let shared = SessionManager()
    var username = "Duncan"
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print(AppSession.shared.username)
    }
}

Wenn Sie nach einer Aktion Daten abrufen möchten, können Sie NotificationCenter verwenden.

extension Notification.Name {
    static let loggedOut = Notification.Name("loggedOut")
}

@IBAction func logoutAction(_ sender: Any) {
    NotificationCenter.default.post(name: .loggedOut, object: nil)
}

NotificationCenter.default.addObserver(forName: .loggedOut, object: nil, queue: OperationQueue.main) { (notify) in
    print("User logged out")
}
Yusuf Demirci
quelle