Frage Übergeben von Daten zwischen View Controllern


Ich bin neu in iOS und Objective-C und dem ganzen MVC-Paradigma und ich bleibe dabei:

Ich habe eine Ansicht, die als Dateneingabeformular dient, und ich möchte dem Benutzer die Möglichkeit geben, mehrere Produkte auszuwählen. Die Produkte werden in einer anderen Ansicht mit einem aufgelistet UITableViewController und ich habe mehrere Auswahlen aktiviert.

Meine Frage ist, wie übertrage ich die Daten von einer Ansicht zur anderen? Ich werde die Auswahl auf dem halten UITableView in einem Array, aber wie übertrage ich das dann zurück an die vorherige Dateneingabe Formularansicht, so dass es zusammen mit den anderen Daten zu Kerndaten bei der Einreichung des Formulars gespeichert werden kann?

Ich habe herumgesurft und einige Leute gesehen, die ein Array im App-Delegaten deklariert haben. Ich habe etwas über Singletons gelesen, verstehe aber nicht, was das ist, und ich lese etwas über das Erstellen eines Datenmodells.

Was wäre die richtige Art und Weise dies auszuführen und wie würde ich damit umgehen?


1205
2018-03-06 12:43


Ursprung


Antworten:


Diese Frage scheint hier auf Stackoverflow sehr populär zu sein, also dachte ich, ich würde versuchen, eine bessere Antwort zu geben und Leuten zu helfen, die wie ich in der Welt von iOS anfangen.

Ich hoffe, dass diese Antwort klar genug ist, dass die Leute es verstehen und ich nichts verpasst habe.

Weiterleiten von Daten

Weiterleiten von Daten an einen View-Controller von einem anderen View-Controller. Sie würden diese Methode verwenden, wenn Sie ein Objekt / einen Wert von einem Ansichtscontroller an einen anderen Ansichtscontroller übergeben möchten, den Sie möglicherweise an einen Navigationsstapel weitergeben.

Für dieses Beispiel werden wir haben ViewControllerA und ViewControllerB

Um ein zu übergeben BOOL Wert von ViewControllerA zu ViewControllerB wir würden folgendes tun.

  1. im ViewControllerB.h Erstellen Sie eine Eigenschaft für die BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. im ViewControllerA du musst es erzählen ViewControllerB also benutze ein

    #import "ViewControllerB.h"
    

    Dann wo Sie die Ansicht zB laden möchten. didSelectRowAtIndex oder einige IBAction Sie müssen die Eigenschaft festlegen ViewControllerB bevor Sie es auf den Nav-Stack schieben.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    Dies wird eingestellt isSomethingEnabled im ViewControllerB zu BOOL Wert YES.

Weitergabe von Daten mit Segues weiterleiten

Wenn Sie Storyboards verwenden, verwenden Sie höchstwahrscheinlich Segmente und benötigen dieses Verfahren, um Daten weiterzuleiten. Dies ist ähnlich wie oben, aber anstatt die Daten zu übergeben, bevor Sie den View-Controller drücken, verwenden Sie eine Methode namens

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Also, um eine zu übergeben BOOL von ViewControllerA zu ViewControllerB wir würden folgendes tun:

  1. im ViewControllerB.h Erstellen Sie eine Eigenschaft für die BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. im ViewControllerA du musst es erzählen ViewControllerB also benutze ein

    #import "ViewControllerB.h"
    
  3. Erstellen Sie einen Übergang von ViewControllerA zu ViewControllerB auf dem Storyboard und geben Sie ihm eine Kennung, in diesem Beispiel nennen wir es "showDetailSegue"

  4. Als nächstes müssen wir die Methode hinzufügen ViewControllerA Dies wird aufgerufen, wenn ein Durchgang durchgeführt wird. Aus diesem Grund müssen wir erkennen, welcher Abschnitt aufgerufen wurde, und dann etwas tun. In unserem Beispiel werden wir nachsehen "showDetailSegue" und wenn das ausgeführt wird, werden wir unsere bestehen BOOL Wert zu ViewControllerB

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    Wenn Sie Ihre Ansichten in einen Navigationscontroller eingebettet haben, müssen Sie die obige Methode leicht ändern

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    Dies wird eingestellt isSomethingEnabled im ViewControllerB zu BOOL Wert YES.

Daten zurückgeben

Um Daten zurück zu übertragen ViewControllerB zu ViewControllerA Sie müssen verwenden Protokolle und Delegierte oder BlöckeLetzteres kann als ein lose gekoppelter Mechanismus für Rückrufe verwendet werden.

Um dies zu tun werden wir machen ViewControllerA ein Delegierter von ViewControllerB. Dies erlaubt ViewControllerB um eine Nachricht zurück zu senden ViewControllerA So können wir Daten zurücksenden.

Zum ViewControllerA Delegierter sein ViewControllerB es muss sich anpassen ViewControllerB's Protokoll, das wir spezifizieren müssen. Das sagt ViewControllerA welche Methoden muss es umsetzen?

  1. Im ViewControllerB.h, unter dem #import, aber oben @interface Sie geben das Protokoll an.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. als nächstes noch in der ViewControllerB.h Sie müssen ein einrichten delegate Eigenschaft und synthetisieren in ViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. Im ViewControllerB wir rufen eine Nachricht auf delegate wenn wir den View-Controller aufrufen.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Das ist es für ViewControllerB. Jetzt in ViewControllerA.hSag es ViewControllerA importieren ViewControllerB und entsprechen seinem Protokoll.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. Im ViewControllerA.m Implementieren Sie die folgende Methode aus unserem Protokoll

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. Vor dem Drücken viewControllerB zum Navigationsstapel müssen wir erzählen ViewControllerB Das ViewControllerA ist sein Vertreter, sonst erhalten wir einen Fehler.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

Verweise


1557
2018-03-16 11:39



Schnell

Es gibt Tonnen und Tonnen von Erklärungen hier und rund um StackOverflow, aber wenn du ein Anfänger bist, der einfach etwas Grundlegendes zur Arbeit bringt, dann schau dir dieses YouTube-Tutorial an (es hat mir geholfen, endlich zu verstehen, wie es geht).

Weiterleiten von Daten an den nächsten View Controller

Das folgende Beispiel basiert auf dem Video. Die Idee besteht darin, eine Zeichenfolge vom Textfeld im First View Controller an die Bezeichnung im Second View Controller zu übergeben.

enter image description here

Erstellen Sie das Storyboard-Layout im Interface Builder. Um den Übergang zu machen, musst du nur Steuerung Klicken Sie auf den Button und ziehen Sie ihn zum zweiten View Controller.

Erster Blick Controller

Der Code für den First View Controller lautet

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Zweiter Ansichten-Controller

Und der Code für den Second View Controller ist

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

Vergiss nicht

  • Schließen Sie die Steckdosen für die UITextField und das UILabel.
  • Setzen Sie den ersten und zweiten View-Controller auf die entsprechenden Swift-Dateien in IB.

Zurückgeben von Daten an den vorherigen View Controller

Um Daten vom zweiten Ansichtscontroller an den ersten Ansichtscontroller zu übertragen, verwenden Sie ein Protokoll und ein Delegierter. Dieses Video ist ein sehr übersichtlicher Ablauf dieses Prozesses:

Das folgende Beispiel basiert auf dem Video (mit einigen Änderungen).

enter image description here

Erstellen Sie das Storyboard-Layout im Interface Builder. Nochmal, um die Überfahrt zu machen, einfach Steuerung Ziehen Sie von der Schaltfläche zum zweiten Ansichts-Controller. Setzen Sie die Überschneidungskennung auf showSecondViewController. Vergessen Sie auch nicht, die Ausgänge und Aktionen mit den Namen im folgenden Code zu verbinden.

Erster Blick Controller

Der Code für den First View Controller lautet

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Beachten Sie die Verwendung unserer benutzerdefinierten DataEnteredDelegate Protokoll.

Zweite Ansicht Controller und Protokoll

Der Code für den zweiten View-Controller lautet

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

Notiere dass der protocol befindet sich außerhalb der View Controller-Klasse.

Das ist es. Wenn Sie die App jetzt ausführen, sollten Sie Daten vom zweiten View-Controller an den ersten zurücksenden können.


131
2017-08-11 06:35



Das M in MVC steht für "Model" und im MVC-Paradigma besteht die Rolle von Modellklassen darin, die Daten eines Programms zu verwalten. Ein Modell ist das Gegenteil einer Ansicht - eine Ansicht weiß, wie man Daten anzeigt, aber sie weiß nicht, was sie mit Daten tun soll, während ein Modell alles darüber weiß, wie man mit Daten arbeitet, aber nichts darüber, wie man es darstellt. Modelle können kompliziert sein, müssen es aber nicht sein - das Modell für Ihre App könnte so einfach sein wie ein Array von Strings oder Wörterbüchern.

Die Rolle eines Controllers besteht darin, zwischen Ansicht und Modell zu vermitteln. Daher benötigen sie einen Verweis auf ein oder mehrere View-Objekte und ein oder mehrere Modellobjekte. Angenommen, Ihr Modell besteht aus einem Array von Wörterbüchern, wobei jedes Wörterbuch eine Zeile in Ihrer Tabelle darstellt. Die Stammansicht für Ihre App zeigt diese Tabelle an und ist möglicherweise dafür verantwortlich, das Array aus einer Datei zu laden. Wenn der Benutzer beschließt, der Tabelle eine neue Zeile hinzuzufügen, tippen sie auf eine Schaltfläche, und Ihr Controller erstellt ein neues (änderbares) Wörterbuch und fügt es dem Array hinzu. Um die Zeile auszufüllen, erstellt der Controller einen Detailansicht-Controller und gibt ihm das neue Wörterbuch. Der Detailansicht-Controller füllt das Wörterbuch aus und kehrt zurück. Das Wörterbuch ist bereits Teil des Modells, also muss nichts anderes passieren.


118
2018-03-06 13:49



Es gibt verschiedene Möglichkeiten, wie Daten in einer anderen Klasse in iOS empfangen werden können. Beispielsweise -

  1. Direkte Initialisierung nach der Zuweisung einer anderen Klasse.
  2. Delegation - um Daten zurück zu geben
  3. Benachrichtigung - für die gleichzeitige Übertragung von Daten an mehrere Klassen
  4. Speichern in NSUserDefaults - um später darauf zuzugreifen
  5. Singleton-Klassen
  6. Datenbanken und andere Speichermechanismen wie Plist usw.

Aber für das einfache Szenario, einen Wert an eine andere Klasse zu übergeben, deren Zuweisung in der aktuellen Klasse erfolgt, wäre die gebräuchlichste und bevorzugte Methode die direkte Einstellung von Werten nach der Zuweisung. Dies geschieht wie folgt:

Wir können es mit zwei Controllern verstehen - Controller1 und Controller2 

Angenommen, in der Controller1-Klasse möchten Sie das Controller2-Objekt erstellen und es mit einem String-Wert übergeben, der übergeben wird. Dies kann wie folgt geschehen:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

In der Implementierung der Controller2-Klasse wird diese Funktion als

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

Sie können die Eigenschaften der Controller2-Klasse auch auf ähnliche Weise wie folgt festlegen:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

Um mehrere Werte zu übergeben, können Sie die folgenden Parameter verwenden:

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date]; 

Oder wenn Sie mehr als 3 Parameter übergeben müssen, die sich auf ein gemeinsames Feature beziehen, können Sie die Werte in einer Model-Klasse speichern und dieses ModelObject an die nächste Klasse übergeben

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

Also kurz - wenn du willst -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

Hoffe das hilft


85
2018-04-08 10:24



Nach mehr Forschung schien es, dass Protokolle und Delegierte der richtige / Apple bevorzugte Weg ist, dies zu tun.

Ich habe dieses Beispiel benutzt

Daten zwischen View-Controllern und anderen Objekten freigeben @ iPhone Entwickler SDK

Arbeitete gut und erlaubte mir, einen String und ein Array zwischen meinen Ansichten vor und zurück zu übergeben.

Danke für deine Hilfe


74
2018-03-13 21:20



Ich finde die einfachste und eleganteste Version mit vorbeifahrenden Blöcken. Lassen Sie uns den View-Controller nennen, der auf zurückgegebene Daten als "A" wartet und den View-Controller als "B" zurückgibt. In diesem Beispiel möchten wir 2 Werte erhalten: erstens von Typ1 und zweitens von Typ2.

Unter der Annahme, dass wir das Storyboard verwenden, setzt der erste Controller den Rückrufblock, zum Beispiel während der Vorbereitung der Segmente:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

und "B" View Controller sollte die Callback-Eigenschaft BViewController.h deklarieren:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

Dann in der Implementierungsdatei BViewController.m, nachdem wir die gewünschten Werte für die Rückgabe des Callbacks erhalten haben:

if (self.callback)
    self.callback(value1, value2);

Eine Sache, an die man sich erinnern sollte, ist, dass die Verwendung von Block oft starke und __leichte Referenzen wie erklärt verwalten muss Hier


59
2017-10-14 18:11



Es gibt einige gute Informationen in vielen der gegebenen Antworten, aber keine beantwortet die Frage vollständig.

Die Frage fragt nach dem Weiterleiten von Informationen zwischen Ansichtscontrollern. Das angegebene Beispiel fragt nach der Weitergabe von Informationen zwischen den Ansichten, aber angesichts der selbsternannten Neuheit für iOS bedeutete das ursprüngliche Poster wahrscheinlich zwischen viewControllern, nicht zwischen Ansichten (ohne Einbeziehung der ViewControllers). Es scheint, dass sich alle Antworten auf zwei View-Controller konzentrieren, aber was ist, wenn die App mehr als zwei View-Controller in den Informationsaustausch einbeziehen muss?

Das ursprüngliche Plakat fragte auch nach Singletons und die Verwendung der AppDelegieren. Diese Fragen müssen beantwortet werden.

Um anderen zu helfen, die diese Frage betrachten, die eine vollständige Antwort wollen, werde ich versuchen, sie zu liefern.

Anwendungsszenarien

Anstatt eine hoch hypothetische, abstrakte Diskussion zu führen, hilft es, konkrete Anwendungen im Auge zu behalten. Um eine Zwei-Ansichten-Controller-Situation und eine Mehr-als-Zwei-Ansicht-Controller-Situation zu definieren, werde ich zwei konkrete Anwendungsszenarien definieren.

Szenario eins: Maximal zwei View-Controller müssen Informationen austauschen. Siehe Diagramm eins.

diagram of original problem

In der Anwendung gibt es zwei View-Controller. Es gibt einen ViewControllerA (Dateneingabeformular) und View Controller B (Produktliste). Die in der Produktliste ausgewählten Elemente müssen mit den Elementen übereinstimmen, die im Textfeld des Dateneingabeformulars angezeigt werden. In diesem Szenario müssen ViewControllerA und ViewControllerB direkt miteinander und keine anderen View-Controller kommunizieren.

Szenario zwei: Mehr als zwei View-Controller müssen dieselben Informationen teilen. Siehe Diagramm zwei.

home inventory application diagram

In der Anwendung gibt es vier View-Controller. Es ist eine tab-basierte Anwendung zum Verwalten von Home-Inventar. Drei View-Controller präsentieren unterschiedlich gefilterte Ansichten derselben Daten:

  • ViewControllerA - Luxusartikel
  • ViewControllerB - Nicht versicherte Artikel
  • ViewControllerC - gesamtes Home-Inventar
  • ViewControllerD - Neues Artikelformular hinzufügen

Jedes Mal, wenn ein einzelnes Element erstellt oder bearbeitet wird, muss es auch mit den anderen View-Controllern synchronisiert werden. Wenn beispielsweise ein Boot in ViewControllerD hinzugefügt wird, es jedoch noch nicht versichert ist, muss das Boot angezeigt werden, wenn der Benutzer zu ViewControllerA (Luxusartikel) und ViewControllerC (Gesamtes Heiminventar) wechselt, aber nicht, wenn der Benutzer zu ihm geht ViewControllerB (nicht versicherte Artikel). Wir müssen uns damit beschäftigen, nicht nur neue Elemente hinzuzufügen, sondern auch Elemente zu löschen (die von jedem der vier Ansichts-Controller zugelassen werden können) oder vorhandene Elemente zu bearbeiten (die unter "Neues Element hinzufügen" zulässig sind) zum Bearbeiten).

Da alle View-Controller die gleichen Daten gemeinsam nutzen müssen, müssen alle vier View-Controller synchron bleiben. Daher muss eine Kommunikation mit allen anderen View-Controllern stattfinden, wenn ein einzelner View-Controller die zugrunde liegenden Daten ändert. Es sollte ziemlich offensichtlich sein, dass nicht jeder View-Controller in diesem Szenario direkt mit dem anderen View-Controller kommunizieren soll. Falls es nicht offensichtlich ist, überlegen Sie, ob wir 20 verschiedene View-Controller haben (anstatt nur 4). Wie schwierig und fehleranfällig wäre es, jeden der anderen 19 View-Controller zu benachrichtigen, wenn ein View-Controller eine Änderung vornimmt?

Die Lösungen: Delegierte und das Beobachtermuster und Singletons

Im ersten Szenario haben wir mehrere brauchbare Lösungen, wie andere Antworten gegeben haben

  • Übergänge
  • Delegierte
  • Eigenschaften direkt auf View-Controllern festlegen
  • NSUserDefaults (eigentlich eine schlechte Wahl)

In Szenario zwei haben wir andere praktikable Lösungen:

  • Beobachtermuster
  • Singletons

EIN Singleton ist eine Instanz einer Klasse, wobei diese Instanz die einzige während ihrer Lebensdauer existierende Instanz ist. Ein Singleton hat seinen Namen von der Tatsache, dass es die einzige Instanz ist. Normalerweise haben Entwickler, die Singletons verwenden, spezielle Klassenmethoden, um auf sie zuzugreifen.

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Jetzt, wo wir verstehen, was ein Singleton ist, wollen wir diskutieren, wie ein Singleton in das Beobachtermuster passt. Das Beobachtermuster wird für ein Objekt verwendet, um auf Änderungen durch ein anderes Objekt zu reagieren. Im zweiten Szenario haben wir vier verschiedene View-Controller, die alle über Änderungen an den zugrunde liegenden Daten informiert werden möchten. Die "zugrunde liegenden Daten" sollten zu einer einzigen Instanz, einem Singleton, gehören. Das "Wissen über Änderungen" wird erreicht, indem Änderungen am Singleton beobachtet werden.

Die Home-Inventory-Anwendung würde eine einzelne Instanz einer Klasse haben, die zum Verwalten einer Liste von Inventarelementen vorgesehen ist. Der Manager würde eine Sammlung von Haushaltsgegenständen verwalten. Folgendes ist eine Klassendefinition für den Datenmanager:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

Wenn sich die Sammlung von Elementen des Home-Inventars ändert, müssen die View-Controller auf diese Änderung aufmerksam gemacht werden. Die obige Klassendefinition macht es nicht offensichtlich, wie dies geschehen wird. Wir müssen dem Beobachtermuster folgen. Die View-Controller müssen den sharedManager formal beobachten. Es gibt zwei Möglichkeiten, ein anderes Objekt zu beobachten:

  • Schlüssel-Wert-Beobachtung (KVO)
  • NSNotifikationszentrum

In Szenario zwei haben wir keine einzige Eigenschaft des HouseholdInventoryManager, die mit KVO beobachtet werden konnte. Da wir keine einzige Eigenschaft haben, die leicht beobachtbar ist, muss das Beobachtermuster in diesem Fall mit NSNotificationCenter implementiert werden. Jeder der vier View-Controller würde Benachrichtigungen abonnieren, und der SharedManager würde bei Bedarf Benachrichtigungen an das Benachrichtigungscenter senden. Der Inventar-Manager muss nichts über die View-Controller oder Instanzen anderer Klassen wissen, die möglicherweise wissen möchten, wann sich die Sammlung von Inventarelementen ändert. Das NSNotificationCenter kümmert sich um diese Implementierungsdetails. Die View-Controller abonnieren einfach Benachrichtigungen und der Datenmanager sendet einfach Benachrichtigungen.

Viele Einsteiger nutzen die Tatsache, dass es immer genau einen gibt Anwendungsbeauftragter in der Lebensdauer der Anwendung, die global zugänglich ist. Anfänger verwenden diese Tatsache, um Objekte und Funktionen in das AppDelegate zu stopfen, um den Zugriff von überall in der Anwendung zu erleichtern. Nur weil das AppDelegate ein Singleton ist, bedeutet das nicht, dass es alle anderen Singletons ersetzen sollte. Dies ist eine schlechte Übung, da es eine Klasse zu sehr belastet und gute objektorientierte Praktiken bricht. Jede Klasse sollte eine klare Rolle haben, die leicht erklärt werden kann, oft nur durch den Namen der Klasse.

Jedes Mal, wenn der Anwendungsdelegat aufgebläht wird, sollten Sie beginnen, die Funktionalität in Singletons zu entfernen. Beispielsweise sollte der Core Data Stack nicht im AppDelegate verbleiben, sondern stattdessen in eine eigene Klasse, eine coreDataManager-Klasse, eingefügt werden.

Verweise


46
2018-04-05 22:04



Es gibt mehrere Methoden zum Teilen von Daten.

  1. Sie können Daten immer mit verwenden NSUserDefaults. Legen Sie den Wert fest, den Sie für einen Schlüssel Ihrer Wahl freigeben möchten, und ermitteln Sie den Wert von NSUserDefault mit diesem Schlüssel in der nächsten Ansicht Controller verbunden.

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
    
  2. Sie können einfach eine Eigenschaft in erstellen viewcontrollerA. Erstelle ein Objekt von viewcontrollerA im viewcontrollerB und weisen Sie dieser Eigenschaft den gewünschten Wert zu.

  3. Sie können auch benutzerdefinierte Delegaten dafür erstellen.


37
2017-09-27 10:38



Es ist interessanter, Daten von ViewController 2 (Ziel) an ViewController 1 (Source) zu übergeben. Angenommen, Sie verwenden storyBoard, sind das alles, was ich herausgefunden habe:

  • Delegieren
  • Benachrichtigung
  • Benutzervorgaben
  • Singleton

Diese wurden bereits hier besprochen.

Ich habe festgestellt, dass es mehrere Möglichkeiten gibt:

-Bei Rückfragen:

benutze es in der prepareForSegue Methode in der VC1

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

-Verwenden von Storyboards Abwickeln (Beenden)

Implementieren Sie eine Methode mit einem UIStoryboardSegue-Argument in VC 1 wie folgt:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

Im StoryBoard haken Sie den "Zurück" -Knopf zum grünen Ausgang Schaltfläche (Abwickeln) des VC.  Jetzt haben Sie einen Übergang, der "zurückgeht", damit Sie den Eigenschaft destinationViewController in prepareForSegue von VC2 und Ändern Sie eine Eigenschaft von VC1, bevor es zurückgeht.

  • Eine weitere Möglichkeit, Storyboards und Wind (Exit) zu verwenden - Sie können Verwenden Sie die Methode, die Sie in VC1 geschrieben haben

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 
    

    Und in prepareForSegue von VC1 können Sie jede Eigenschaft ändern, die Sie teilen möchten.

In beiden Abwicklungsoptionen können Sie die Tag-Eigenschaft der Schaltfläche festlegen und einchecken         die prepareForSegue.

Hoffe, ich habe etwas zur Diskussion hinzugefügt.

:) Prost.


37
2018-04-11 00:33