it-swarm.com.de

Daten zwischen View-Controllern übergeben

Ich bin neu bei iOS und Objective-C und dem gesamten MVC-Paradigma. Ich bleibe dabei bei Folgendem:

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

Meine Frage ist, wie übertrage ich die Daten von einer Ansicht zu einer anderen? Ich werde die Auswahlmöglichkeiten für die Variable UITableView in einem Array enthalten, aber wie gebe ich diese dann an die vorherige Formularansicht zurück, damit sie zusammen mit den anderen Daten beim Senden des Formulars zusammen mit Core Data gespeichert werden kann?

Ich habe herumgesurft und gesehen, wie einige Leute im App-Delegierten ein Array deklarieren. Ich habe etwas über Singletons gelesen, verstehe aber nicht, was es ist und ich habe etwas über das Erstellen eines Datenmodells gelesen.

Was wäre der richtige Weg, dies zu tun und wie würde ich das anstellen?

1254
Matt Price

Diese Frage scheint bei stackoverflow sehr beliebt zu sein. Ich dachte, ich würde versuchen, eine bessere Antwort zu geben, um Leuten zu helfen, die in der Welt von iOS wie mir anfangen.

Ich hoffe, dass diese Antwort für die Leute klar genug ist und dass ich nichts übersehen habe.

Weiterleiten von Daten

Weiterleiten von Daten an einen View Controller von einem anderen View Controller aus. Sie würden diese Methode verwenden, wenn Sie ein Objekt/einen Wert von einem View-Controller an einen anderen View-Controller übergeben möchten, den Sie möglicherweise in einen Navigations-Stack verschieben.

Für dieses Beispiel haben wir ViewControllerA und ViewControllerB

Um einen BOOL-Wert von ViewControllerA an ViewControllerB zu übergeben, würden wir Folgendes tun.

  1. in ViewControllerB.h eine Eigenschaft für die BOOL erstellen

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. in ViewControllerA musst du etwas über ViewControllerB sagen, also benutze ein 

    #import "ViewControllerB.h"
    

    Dort, wo Sie die Ansicht laden möchten, z. didSelectRowAtIndex oder einige IBAction müssen Sie die Eigenschaft in ViewControllerB setzen, bevor Sie sie in den Nav-Stack verschieben.

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

    Dies setzt isSomethingEnabled in ViewControllerB auf BOOL Wert YES.

Weiterleiten von Daten über Segmente

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 vor dem Push des View-Controllers zu übergeben, verwenden Sie eine aufgerufene Methode

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

Um eine BOOL von ViewControllerA an ViewControllerB zu übergeben, würden wir Folgendes tun:

  1. in ViewControllerB.h eine Eigenschaft für die BOOL erstellen

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. in ViewControllerA musst du etwas über ViewControllerB sagen, also benutze ein

    #import "ViewControllerB.h"
    
  3. Erstellen Sie im Storyboard ein Segment von ViewControllerA bis ViewControllerB und geben Sie ihm eine Kennung. In diesem Beispiel nennen wir es "showDetailSegue".

  4. Als Nächstes müssen wir die Methode ViewControllerA hinzufügen, die aufgerufen wird, wenn ein Segment ausgeführt wird. Aus diesem Grund müssen wir ermitteln, welches Segment aufgerufen wurde, und dann etwas tun. In unserem Beispiel werden wir nach "showDetailSegue" suchen und wenn dies ausgeführt wird, übergeben wir unseren BOOL-Wert an 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 setzt isSomethingEnabled in ViewControllerB auf BOOL Wert YES.

Daten zurückgeben

Um Daten von ViewControllerB an ViewControllerA zurückzuschicken, müssen Sie Protokolle und Delegierte oder Blöcke verwenden. Letzteres kann als lose gekoppelter Mechanismus für Rückrufe verwendet werden.

Dazu machen wir ViewControllerA zu einem Delegierten von ViewControllerB. Dadurch kann ViewControllerB eine Nachricht an ViewControllerA zurücksenden, sodass wir Daten zurücksenden können.

Damit ViewControllerA ein Delegierter von ViewControllerB ist, muss es dem Protokoll von ViewControllerB entsprechen, das wir angeben müssen. Dies sagt ViewControllerA, welche Methoden es implementieren muss.

  1. In ViewControllerB.h, unterhalb von #import, aber oberhalb von @interface geben Sie das Protokoll an.

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

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. In ViewControllerB rufen wir eine Nachricht über die delegate auf, wenn der View-Controller geöffnet wird.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Das war's für ViewControllerB. Geben Sie jetzt in ViewControllerA.hViewControllerA an, ViewControllerB zu importieren und dessen Protokoll einzuhalten.

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

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. Bevor Sie viewControllerB in den Navigationsstapel verschieben, müssen Sie ViewControllerB mitteilen, dass ViewControllerA sein Stellvertreter ist. Andernfalls wird ein Fehler angezeigt.

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

Verweise

  1. Delegierung verwenden, um mit anderen View-Controllern zu kommunizieren im View Controller-Programmierhandbuch
  2. Delegiertenmuster

NSNotification Center Es ist eine andere Möglichkeit, Daten zu übergeben. 

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

Zurückgeben von Daten von einer Klasse an eine andere (Eine Klasse kann ein beliebiger Controller, ein Netzwerk-/Sitzungsmanager, eine UIView-Unterklasse oder eine andere Klasse sein.)

Blöcke sind anonyme Funktionen.

In diesem Beispiel werden Daten von Controller B an Controller A übergeben.

einen Block definieren

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

add Block Handler (Listener) wo Sie einen Wert benötigen (zum Beispiel benötigen Sie Ihre API-Antwort in ControllerA oder benötigen Sie ContorllerB-Daten auf A)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

Gehe zu Controller B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

feuerblock

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

Ein weiteres Arbeitsbeispiel für Blöcke

1599
Matt Price

Schnell

Hier und in StackOverflow gibt es jede Menge Erklärungen, aber wenn Sie als Anfänger nur versuchen, etwas Grundlegendes zum Laufen zu bringen, schauen Sie sich dieses YouTube-Tutorial an (es hat mir geholfen, endlich zu verstehen, wie es geht).

Weitergabe von Daten an den nächsten View Controller

Das folgende Beispiel basiert auf dem Video. Die Idee ist, eine Zeichenfolge aus dem Textfeld im First View Controller an die Beschriftung im Second View Controller zu übergeben.

enter image description here

Erstellen Sie das Storyboard-Layout im Interface Builder. Um den Übergang zu schaffen, müssen Sie nur Control Klicken Sie auf die Schaltfläche und ziehen Sie sie zum Second View Controller.

First View 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!
    }

}

Second View 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 Ausgänge für UITextField und UILabel an.
  • Stellen Sie den ersten und den zweiten View Controller auf die entsprechenden Swift-Dateien in IB ein.

Daten an den vorherigen View Controller zurückgeben

Verwenden Sie ein Protokoll und einen Delegaten , um Daten von dem zweiten Ansichtscontroller an den ersten Ansichtscontroller zurückzugeben. Dieses Video ist ein sehr anschaulicher Überblick über diesen Prozess:

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

enter image description here

Erstellen Sie das Storyboard-Layout im Interface Builder. Nochmals, um den Übergang zu schaffen, einfach Control Ziehen Sie von der Schaltfläche zum Second View Controller. Setzen Sie die Segue-ID auf showSecondViewController. Vergessen Sie auch nicht, die Ausgänge und Aktionen mit den Namen im folgenden Code zu verbinden.

First View 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 unseres benutzerdefinierten Protokolls DataEnteredDelegate.

Second View Controller und Protokoll

Der Code für den zweiten Ansichtscontroller 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)
    }
}

Beachten Sie, dass sich protocol außerhalb der View Controller-Klasse befindet.

Das ist es. Wenn Sie die App jetzt ausführen, sollten Sie in der Lage sein, Daten vom zweiten View-Controller an den ersten zurückzusenden.

164
Suragch

Das M in MVC ist für "Model" und im MVC-Paradigma besteht die Rolle der Modellklassen darin, die Daten eines Programms zu verwalten. Ein Modell ist das Gegenteil einer Ansicht. Eine Ansicht kann Daten anzeigen, weiß jedoch nicht, was mit Daten zu tun ist, wohingegen ein Modell alles über die Arbeit mit Daten weiß, aber nichts über die Anzeige. Modelle können kompliziert sein, müssen es aber nicht sein - das Modell für Ihre App ist möglicherweise so einfach 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 Ansichtsobjekte 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. In der Stammansicht Ihrer App wird diese Tabelle angezeigt. Möglicherweise ist das Array aus einer Datei geladen. Wenn der Benutzer beschließt, der Tabelle eine neue Zeile hinzuzufügen, tippen Sie auf eine Schaltfläche, und Ihr Controller erstellt ein neues (verä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, sodass nichts anderes passieren muss.

122
Caleb

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

  1. Direkte Initialisierung nach Zuweisung einer anderen Klasse.
  2. Delegierung - zur Weitergabe von Daten 
  3. Benachrichtigung - zum Senden von Daten an mehrere Klassen gleichzeitig
  4. Speichern in NSUserDefaults - um später darauf zuzugreifen
  5. Singleton-Klassen 
  6. Datenbanken und andere Speichermechanismen wie plist usw.

Für das einfache Szenario der Übergabe eines Werts an eine andere Klasse, deren Zuordnung in der aktuellen Klasse erfolgt, wäre die gebräuchlichste und bevorzugte Methode das direkte Setzen von Werten nach der Zuordnung. Dies geschieht wie folgt:

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

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

- (void)pushToController2 {

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

Bei der Implementierung der Klasse Controller2 wird diese Funktion 

@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 direkt 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]; 

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 in Kürze, wenn Sie wollen -

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

87
borncrazy

Nach weiteren Nachforschungen schien es, dass Protokolle und Delegierte der richtige Weg sind, den Apple bevorzugt.

Am Ende habe ich dieses Beispiel verwendet

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

Funktionierte gut und erlaubte mir, eine Zeichenfolge und ein Array vor und zurück zwischen meinen Ansichten zu übergeben.

Danke für deine Hilfe

78
Matt Price

Ich finde die einfachste und eleganteste Version mit Durchlaufblöcken. Geben Sie dem View-Controller einen Namen, der auf zurückgegebene Daten als "A" wartet und den View-Controller als "B" zurückgibt. In diesem Beispiel möchten wir zwei Werte erhalten: den ersten von Typ1 und den zweiten von Typ2.

Angenommen, wir verwenden Storyboard, legt der erste Controller einen Callback-Block fest, zum Beispiel während der Vorbereitung des Segments:

- (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 sollten die Callback-Eigenschaft BViewController.h deklarieren:

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

Als in der Implementierungsdatei BViewController.m, nachdem wir gewünschte Werte für die Rückgabe unseres Callbacks haben, sollte aufgerufen werden

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

Dabei ist zu beachten, dass bei der Verwendung von Block häufig starke und __schwache Referenzen verwaltet werden müssen, wie erklärt hier

61
Leszek Zarna

Viele der Antworten geben einige gute Informationen, aber die Antwort ist nicht vollständig.

Die Frage fragt nach der Weitergabe von Informationen zwischen View-Controllern. In diesem speziellen Beispiel wird nach dem Weitergeben von Informationen zwischen Ansichten gefragt. Angesichts der neuen Selbstverständlichkeit von iOS war das ursprüngliche Poster jedoch wahrscheinlich für die Ansicht zwischen ViewControllern und nicht zwischen Ansichten (ohne Beteiligung der ViewControllers) gemeint. Es scheint, dass sich alle Antworten auf zwei Ansichtscontroller konzentrieren, aber was ist, wenn die App mehr als zwei Ansichtscontroller in den Informationsaustausch einbeziehen muss? 

Das ursprüngliche Poster fragte auch nach Singletons und der Verwendung von AppDelegate. Diese Fragen müssen beantwortet werden.

Um allen anderen Personen zu helfen, die sich diese Frage ansehen und eine vollständige Antwort wünschen, werde ich versuchen, sie zu beantworten.

Anwendungsszenarien

Anstatt eine höchst hypothetische, abstrakte Diskussion zu führen, hilft es, konkrete Anwendungen im Auge zu behalten. Um bei der Definition einer Situation mit zwei Ansichten und einer Situation mit mehr als zwei Ansichten zu helfen, werde ich zwei konkrete Anwendungsszenarien definieren.

Szenario 1: Maximal zwei View-Controller müssen Informationen gemeinsam nutzen. __ Siehe Diagramm eins. 

diagram of original problem

In der Anwendung gibt es zwei Ansichtscontroller. Es gibt ein ViewControllerA (Dateneingabeformular) und View Controller B (Produktliste). Die in der Produktliste ausgewählten Artikel müssen mit den im Textfeld des Dateneingabeformulars angezeigten Elementen übereinstimmen. In diesem Szenario müssen ViewControllerA und ViewControllerB direkt miteinander und mit keinen anderen View-Controllern kommunizieren. 

Szenario zwei: Mehr als zwei Ansichtssteuerungen müssen die gleichen Informationen gemeinsam nutzen. _ Siehe Diagramm zwei.

home inventory application diagram

In der Anwendung gibt es vier Ansichtscontroller. Es ist eine tabulatorbasierte Anwendung zum Verwalten des Home-Inventars. Drei Ansichtscontroller bieten unterschiedlich gefilterte Ansichten derselben Daten:

  • ViewControllerA - Luxusartikel 
  • ViewControllerB - Nicht versicherte Artikel
  • ViewControllerC - Gesamtes Inventar 
  • ViewControllerD - Neues Formular hinzufügen

Jedes Mal, wenn ein einzelnes Element erstellt oder bearbeitet wird, muss es auch mit den anderen View-Controllern synchronisiert werden. Wenn wir beispielsweise ein Boot in ViewControllerD hinzufügen, aber noch nicht versichert sind, muss das Boot erscheinen, wenn der Benutzer zu ViewControllerA (Luxury Items) und auch ViewControllerC (Entire Home Inventory) wechselt, jedoch nicht, wenn der Benutzer zu geht ViewControllerB (Nicht versicherte Gegenstände). Wir müssen uns nicht nur um das Hinzufügen neuer Elemente kümmern, sondern auch um das Löschen von Elementen (die möglicherweise von einem der vier Ansichtscontroller aus zulässig sind) oder das Bearbeiten vorhandener Elemente (die möglicherweise über das "Formular zum Hinzufügen neuer Elemente" zulässig sind) zur Bearbeitung).

Da alle View-Controller dieselben Daten gemeinsam nutzen müssen, müssen alle vier View-Controller synchron bleiben. Daher muss eine Kommunikation mit allen anderen View-Controllern hergestellt werden, wenn ein einzelner View-Controller die zugrunde liegenden Daten ändert. Es sollte offensichtlich sein, dass in diesem Szenario nicht jeder View Controller direkt mit jedem anderen View Controller kommunizieren soll. Falls es nicht offensichtlich ist, überlegen Sie, ob wir 20 verschiedene Ansichtscontroller hätten (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 Observer Pattern und Singletons

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

  • segues
  • delegierte
  • eigenschaften auf View-Controllern direkt festlegen
  • NSUserDefaults (eigentlich eine schlechte Wahl)

Im zweiten Szenario haben wir andere praktikable Lösungen:

  • Beobachtermuster 
  • Singletons

Ein singleton ist eine Instanz einer Klasse. Diese Instanz ist die einzige Instanz, die während ihrer Lebensdauer existiert. Ein Singleton erhält seinen Namen von der Tatsache, dass es sich um eine einzelne Instanz handelt. 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;
}

Nun, da 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 eines anderen Objekts zu reagieren. Im zweiten Szenario haben wir vier verschiedene View-Controller, die alle über Änderungen an den zugrunde liegenden Daten erfahren möchten. Die "zugrunde liegenden Daten" sollten zu einer einzelnen Instanz gehören, einem Singleton. Das "Wissen über Änderungen" wird durch das Beobachten von Änderungen erreicht, die am Singleton vorgenommen wurden.Die Home-Inventaranwendung verfügt über eine einzige Instanz einer Klasse, 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

  • NSNotificationCenter.
  • In Szenario 2 haben wir keine einzige Eigenschaft des HouseholdInventoryManagers, die mit KVO beobachtet werden könnte. Da wir keine einzige Eigenschaft haben, die leicht beobachtbar ist, muss das Beobachtermuster in diesem Fall mit NSNotificationCenter implementiert werden. Jeder der vier Ansichtscontroller würde Benachrichtigungen abonnieren, und der sharedManager sendet gegebenenfalls Benachrichtigungen an das Benachrichtigungscenter. Der Inventar-Manager muss nichts über die View-Controller oder Instanzen anderer Klassen wissen, die daran interessiert sein könnten, wenn sich die Sammlung von Inventarelementen ändert. Das NSNotificationCenter kümmert sich um diese Implementierungsdetails. Die View-Controller abonnieren einfach Benachrichtigungen, und der Datenmanager gibt einfach Benachrichtigungen aus.

Viele Einsteigerprogrammierer nutzen die Tatsache, dass es während der gesamten Laufzeit der Anwendung immer genau einen Application Delegate gibt, auf den global zugegriffen werden kann. Anfängliche Programmierer nutzen diese Tatsache, um Objekte und Funktionen in appDelegate zu packen, um von überall aus der Anwendung darauf zugreifen zu können. Nur weil AppDelegate ein Singleton ist, bedeutet das nicht, dass es alle anderen Singletons ersetzen sollte. Dies ist eine schlechte Praxis, da sie eine Klasse zu stark belastet und gegen objektorientierte Praktiken verstößt. Jede Klasse sollte eine klare Rolle haben, die leicht zu erklären ist, oft nur durch den Namen der Klasse.

Jedes Mal, wenn Ihr Anwendungsdelegat aufgebläht wird, müssen Sie die Funktionalität in Singletons entfernen. Der Core Data Stack sollte beispielsweise nicht im AppDelegate belassen werden, sondern sollte in seiner eigenen Klasse, der coreDataManager-Klasse, abgelegt werden.

Verweise 

50
Jason Cross

Das Zurückgeben von Daten von ViewController 2(destination) an ViewController 1(Source) ist die interessantere Sache.

  • Delegieren 
  • Benachrichtigung
  • Benutzervorgaben
  • Singleton

Das wurde hier schon besprochen.

Ich fand, dass es mehr Möglichkeiten gibt:

-Verwendung von blockbacks:

verwenden Sie es in der prepareForSegue-Methode im VC1

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

-Verwendung von Storyboards Abwickeln (Beenden)

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

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

Hängen Sie im Storyboard die Schaltfläche "Zurück" an die grüne Schaltfläche "Beenden " (Abwickeln) des Vc . Jetzt haben Sie ein Segment, das "zurückgeht", so dass Sie die DestinationViewController -Eigenschaft in prepareForSegue von VC2 verwenden können und jede Eigenschaft von VC1.

  • Eine weitere Möglichkeit, Storyboards zu verwenden. Rückgängig machen (Beenden) - Sie können Die in VC1 beschriebene Methode verwenden

    -(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 freigeben möchten.

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

Ich hoffe, ich habe der Diskussion etwas hinzugefügt. 

:) Prost.

38
Yevgeni

Es gibt mehrere Methoden, um Daten gemeinsam zu nutzen.

  1. Sie können Daten jederzeit mit NSUserDefaults freigeben. Legen Sie den Wert fest, den Sie in Bezug auf einen Schlüssel Ihrer Wahl freigeben möchten, und rufen Sie den Wert von NSUserDefault ab, der diesem Schlüssel im Controller der nächsten Ansicht zugeordnet ist. 

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

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

37
Anubrata Santra

Das OP erwähnte zwar nicht die Ansichts-Controller, aber es gab so viele Antworten, dass ich mit einbeziehen wollte, was einige der neuen Funktionen der LLVM ermöglichen, dies zu vereinfachen, wenn Daten von einem Ansichts-Controller an einen anderen weitergegeben werden sollen einige Ergebnisse zurückbekommen.

Storyboard-Segmente, ARC- und LLVM-Blöcke machen dies für mich einfacher denn je. Bei einigen Antworten wurden bereits Storyboards und Abschnitte erwähnt, die sich jedoch immer noch auf Delegierung stützten. Das Definieren von Delegaten funktioniert zwar, aber es ist für manche Benutzer einfacher, Zeiger oder Codeblöcke zu übergeben.

Mit UINavigators und Segues gibt es einfache Möglichkeiten, Informationen an den untergeordneten Controller zu übergeben und die Informationen zurückzubekommen. ARC macht das Übergeben von Zeigern auf von NSObjects abgeleitete Dinge einfach. Wenn Sie möchten, dass der untergeordnete Controller einige Daten für Sie hinzufügt/ändert/ändert, übergeben Sie ihm einen Zeiger auf eine veränderliche Instanz. Blöcke erleichtern das Übergeben von Aktionen. Wenn Sie also möchten, dass der untergeordnete Controller eine Aktion auf Ihrem übergeordneten Controller auslöst, übergeben Sie einen Block. Sie definieren den Block, um eine beliebige Anzahl von Argumenten zu akzeptieren, die für Sie sinnvoll ist. Sie können die API auch so entwerfen, dass sie mehrere Blöcke verwendet, wenn dies besser passt.

Hier sind zwei triviale Beispiele für den Kleber. Der erste ist unkompliziert und zeigt einen für die Eingabe übergebenen Parameter, den zweiten für die Ausgabe.

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

Dieses zweite Beispiel zeigt, wie ein Rückmeldeblock für das zweite Argument übergeben wird. Ich mag die Verwendung von Blöcken, weil sie die relevanten Details in der Quelle - der übergeordneten Ebene - eng zusammenhält.

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}
36
WeakPointer

Wenn Sie Daten von einem Controller an einen anderen übergeben möchten, probieren Sie diesen Code

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }
27
user2998756

Ich habe lange nach dieser Lösung gesucht, Atlast habe ich gefunden. Zunächst deklarieren Sie alle Objekte in Ihrer SecondViewController.h-Datei wie

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

Weisen Sie jetzt in Ihrer Implementierungsdatei den Speicher für diese Objekte zu

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

Nun haben Sie den Speicher für Array und Objekt zugewiesen. Jetzt können Sie diese Erinnerung füllen, bevor Sie diese ViewController drücken.

Gehen Sie zu Ihrem SecondViewController.h und schreiben Sie zwei Methoden

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

in der Implementierungsdatei können Sie die Funktion implementieren 

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

sie erwarten, dass Ihre CustomObject eine Setterfunktion haben muss.

jetzt ist deine grundlegende Arbeit erledigt. Gehen Sie zu der Stelle, an der Sie die Variable SecondViewController drücken möchten, und führen Sie die folgenden Schritte aus

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

Achten Sie auf Rechtschreibfehler. 

25
AsifHabib

Dies ist nicht die Art und Weise, dies zu tun. Sie sollten Delegaten verwenden. Ich nehme an, wir haben zwei View-Controller, ViewController1 und ViewController2. Diese Check-Sache befindet sich im ersten und wenn sich ihr Status ändert, möchten Sie etwas in ViewController2 tun Um dies auf die richtige Weise zu erreichen, sollten Sie Folgendes tun:

Fügen Sie Ihrem Projekt eine neue Datei hinzu (Objective-C-Protokoll) Datei -> Neu, nennen Sie sie jetzt ViewController1Delegate oder was immer Sie möchten, und schreiben Sie diese zwischen die Direktiven @interface und @end

@optional

- (void)checkStateDidChange:(BOOL)checked;

Gehen Sie jetzt zu ViewController2.h und fügen Sie hinzu

#import "ViewController1Delegate.h"

Ändern Sie dann die Definition in

@interface ViewController2: UIViewController<ViewController1Delegate>

Gehen Sie jetzt zu ViewController2.m und fügen Sie in der Implementierung Folgendes hinzu:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Gehen Sie jetzt zu ViewController1.h und fügen Sie die folgende Eigenschaft hinzu:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Wenn Sie nun nach einem Ereignis ViewController1 in ViewController2 erstellen, sollten Sie dies mit NIB-Dateien tun:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Jetzt sind Sie fertig, wenn Sie das in ViewController1 geänderte Prüfereignis feststellen, müssen Sie nur noch das Folgende tun

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

Bitte sagen Sie mir, wenn etwas nicht klar ist, wenn ich Ihre Frage nicht richtig verstanden habe.

21
Boda Taljo

Wenn Sie Daten von einem ViewController an einen anderen ViewController senden möchten, können Sie Folgendes tun:

Nehmen wir an, wir haben viewController: viewControllerA und viewControllerB

Jetzt in viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

In viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

In viewControllerA.m 

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

So können Sie Daten von viewControllerA an viewControllerB übergeben, ohne einen Delegaten festzulegen. ;)

19
Aniruddh Joshi

1. Erstellen Sie die Instanz des ersten View Controllers im zweiten View Controller und nehmen Sie ihre Eigenschaft @property (nonatomic,assign) vor.

2. Weisen Sie die SecondviewController-Instanz dieses View-Controllers zu.

2. Wenn Sie die Auswahl abgeschlossen haben, kopieren Sie das Array in den ersten View Controller. Wenn Sie das SecondView entladen, wird FirstView die Array-Daten speichern.

Hoffe das hilft.

18
kaar3k

Daten zwischen FirstViewController an SecondViewController weitergeben

Zum Beispiel: 

FirstViewController String-Wert als

StrFirstValue = @"first";

so können wir diesen Wert in der zweiten Klasse mit dem folgenden Schritt übergeben

1> Wir müssen ein String-Objekt in der SecondViewController.h-Datei erstellen

NSString *strValue;

2> Die Eigenschaft muss wie unten in der .h-Datei angegeben deklariert werden 

@property (strong, nonatomic)  NSString *strSecondValue;

3> Synthetisieren Sie diesen Wert in der FirstViewController.m-Datei unterhalb der Header-Deklaration

@synthesize strValue;

und in FirstViewController.h:

@property (strong, nonatomic)  NSString *strValue;

4> In FirstViewController, von welcher Methode wir zur zweiten Ansicht navigieren, schreiben Sie bitte den Code in dieser Methode. 

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];
16
Chris Alan

Zur Zeit arbeite ich an einer Open-Source-Lösung für dieses Problem durch ein Projekt namens MCViewFactory, das hier zu finden ist:

https://github.com/YetiHQ/manticore-iosviewfactory

Die Idee ist imitiert das Paradigma von Android, indem eine globale Fabrik verwendet wird, um zu verwalten, welche Ansicht Sie betrachten, und "Intents" verwendet, um Daten zwischen Ansichten zu wechseln und zu übergeben. Die gesamte Dokumentation befindet sich auf der Github-Seite. Hier einige Highlights:

Sie richten alle Ihre Ansichten in XIB-Dateien ein und registrieren sie beim App-Delegierten, während Sie die Factory initialisieren.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

Wenn Sie jetzt in Ihrem VC zu einem neuen VC wechseln und Daten übergeben möchten, erstellen Sie eine neue Absicht und fügen Daten zu seinem Wörterbuch hinzu (SavedInstanceState). Dann legen Sie einfach die aktuelle Absicht der Fabrik fest:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

Alle Ihre diesbezüglichen Ansichten müssen Unterklassen von MCViewController sein, mit denen Sie die neue onResume: -Methode überschreiben können, um auf die übergebenen Daten zugreifen zu können.

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

Ich hoffe, einige von Ihnen finden diese Lösung nützlich/interessant. 

16
user2563044

In meinem Fall habe ich eine Singleton-Klasse verwendet, die als globales Objekt arbeiten kann, um von fast überall in der App auf die Daten zuzugreifen. Als Erstes bauen Sie eine Singleton-Klasse. Lesen Sie bitte die Seite " Wie soll mein Objective-C-Singleton aussehen? " Und um das Objekt global zugänglich zu machen, importieren Sie es einfach in appName_Prefix.pch, das für die Anwendung von import-Anweisungen in allen Klassen gilt Um auf dieses Objekt zuzugreifen und es zu verwenden, habe ich einfach eine Klassenmethode implementiert, um die gemeinsam genutzte Instanz zurückzugeben, die ihre eigenen Variablen enthält

15
petershine

Erstellen Sie die Eigenschaft in next view controller .h und definieren Sie Getter und Setter.

Fügen Sie diesen property in NextVC.h in nextVC hinzu

@property (strong, nonatomic) NSString *indexNumber;

Hinzufügen 

@synthesize indexNumber; in NextVC.m

Und zuletzt

NextVC *vc=[[NextVC alloc]init];

[email protected]"123";

[self.navigationController vc animated:YES];
13
Vivek Yadav

Ich weiß, dass dies ein geschlagenes Thema ist, aber für diejenigen, die diese Frage mit einer schnellen Neigung beantworten möchten und ein einfaches Beispiel wollen, hier meine Methode zum Weiterleiten von Daten, wenn Sie einen Segue verwenden, um herumzukommen.

Es ist ähnlich wie oben, jedoch ohne die Knöpfe, Beschriftungen und dergleichen. Daten einfach von einer Ansicht zur nächsten weitergeben.

Das Storyboard einrichten

Es gibt drei Teile. 

  1. Der Absender
  2. Der Segue
  3. Der Empfänger

Dies ist ein sehr einfaches Ansichtslayout mit einem Abstand zwischen ihnen.


 Very simple view layout. Note : No navigation controller


Hier ist das Setup für den Absender


 The Sender


Hier ist das Setup für den Empfänger.


 The Receiver


Zuletzt das Setup für das Segment.


 The Segue Identifier


Die View Controller

Wir halten das so einfach, also keine Tasten, keine Aktionen, wir verschieben beim Laden der Anwendung einfach Daten vom Sender zum Empfänger und geben den übertragenen Wert an die Konsole aus.

Diese Seite nimmt den ursprünglich geladenen Wert und gibt ihn weiter.

//
//  ViewControllerSender.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"


    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

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

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

Diese Seite sendet beim Laden nur den Wert der Variablen an die Konsole. Zu diesem Zeitpunkt sollte unser Lieblingsfilm in dieser Variablen sein.

//
//  ViewControllerReceiver.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()


        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }



}

So können Sie es angehen, wenn Sie ein Segment verwenden möchten und Ihre Seiten nicht unter einem Navigationscontroller liegen.

Sobald es ausgeführt wird, sollte es automatisch in die Empfängeransicht wechseln und den Wert vom Sender an den Empfänger übergeben, wobei der Wert in der Konsole angezeigt wird.

 Ghost Busters is a classic folks.

Die Delegierung ist die einzige Lösung, die solche Operationen ausführt, wenn Sie .xib-Dateien verwenden. Alle oben beschriebenen Antworten gelten jedoch für storyboard für .xibs-Dateien, die Sie für die Delegierung benötigen. das ist nur Lösung, die du kannst. 

Eine andere Lösung ist, Singleton-Klassenmuster zu verwenden, es einmal zu initialisieren und in Ihrer gesamten App zu verwenden. 

10
user2786888

wenn Sie Daten von ViewControlerOne an ViewControllerTwo übergeben möchten, probieren Sie diese .. 

führen Sie diese in ViewControlerOne.h aus

 @property (nonatomic, strong) NSString *str1;

tun Sie dies in ViewControllerTwo.h

 @property (nonatomic, strong) NSString *str2;

Synthetisieren Sie str2 in ViewControllerTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

führen Sie diese in ViewControlerOne.m aus

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

klicken Sie auf die Schaltflächen Ereignis klicken ..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

tun Sie dies in ViewControllerTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}
10
krushnsinh

Es gibt unzählige Möglichkeiten, dies zu tun, und es ist wichtig, die richtige zu wählen. Eine der größten architektonischen Entscheidungen liegt wahrscheinlich darin, wie der Modellcode in der App gemeinsam genutzt oder darauf zugegriffen wird.

Ich habe vor einiger Zeit einen Blogbeitrag darüber geschrieben: Modellcode teilen . Hier eine kurze Zusammenfassung:

Freigegebene Daten

Ein Ansatz besteht darin, Zeiger auf die Modellobjekte zwischen Ansichtssteuerungen zu teilen. 

  • Brute-Force-Iteration für View-Controller (in Navigation oder Tab Bar Controller), um die Daten festzulegen
  • Setze Daten in prepareForSegue (wenn Storyboards) oder init (falls programmgesteuert)

Da die Vorbereitung für das Segue am häufigsten ist, ist hier ein Beispiel:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

Unabhängiger Zugang

Ein anderer Ansatz besteht darin, einen Bildschirm voller Daten gleichzeitig zu handhaben und anstatt die View-Controller miteinander zu koppeln, koppeln Sie jeden View-Controller mit einer einzelnen Datenquelle, zu der sie unabhängig voneinander gelangen können. 

Die häufigste Art, wie ich das gesehen habe, ist eine Singleton -Instanz. Wenn Ihr Singleton-Objekt DataAccess wäre, könnten Sie Folgendes in der viewDidLoad-Methode von UIViewController ausführen:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

Es gibt Hinzufügungstools, die auch helfen, Daten weiterzugeben:

  • Schlüsselwertbeobachtung
  • NS-Benachrichtigung
  • Kerndatei
  • NSFetchedResultsController
  • Datenquelle

Kerndatei

Das Schöne an Core Data ist, dass es inverse Beziehungen hat. Wenn Sie also nur einem NotesViewController das Notes-Objekt zuweisen möchten, können Sie dies tun, da es eine umgekehrte Beziehung zu etwas anderem wie dem Notizbuch hat. Wenn Sie Daten auf dem Notizbuch im NotesViewController benötigen, können Sie den Objektgraph mit den folgenden Schritten sichern:

let notebookName = note.notebook.name

Lesen Sie mehr dazu in meinem Blog-Beitrag: Modellcode teilen

10
Korey Hinton

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;
10
Mohsin Sabasara

Sie können Daten in App-Delegaten speichern, um über View-Controller in Ihrer Anwendung darauf zuzugreifen. Sie müssen lediglich eine freigegebene Instanz eines App-Delegaten erstellen

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

Zum Beispiel

wenn Sie einen NSArray object *arrayXYZ angeben, können Sie in jedem View-Controller über appDelegate.arrayXYZ darauf zugreifen.

10
ak_tyagi

Ich mag die Idee von Model-Objekten und Mock-Objekten auf der Basis von NSProxy, Daten zu übergeben oder zu verwerfen, wenn der Benutzer auswählt, dass er abgebrochen werden kann. 

Es ist einfach, Daten zu übergeben, da es sich um ein einzelnes Objekt oder um mehrere Objekte handelt. Wenn Sie den UINavigationController-Controller angesprochen haben, können Sie die Referenz zum Modell im Inneren behalten, und alle übergebenen Ansichtscontroller können direkt vom Navigationscontroller darauf zugreifen.

8
highmaintenance

Wenn Sie Daten von einem ViewController an einen anderen ViewController senden möchten, können Sie Folgendes tun:

Nehmen wir an, wir haben viewController: ViewController und NewViewController.

in ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

in ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

In NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

In NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

Auf diese Weise können wir die Daten von einem Viewcontroller an einen anderen Viewcontroller übergeben ...

8
Sabs

Ich habe viele Leute gesehen, die dies mit der didSelectRowAtPath-Methode verkompliziert haben. Ich verwende in meinem Beispiel Core Data.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 Zeilen Code in der Methode und Sie sind fertig. 

7
App Dev Guy

Es gibt viele Antworten auf diese Fragen, die viele verschiedene Möglichkeiten bieten, um eine View Controller-Kommunikation durchzuführen, die tatsächlich funktionieren würde, aber ich sehe nirgendwo, welche davon am besten zu verwenden und welche zu vermeiden sind.

In der Praxis werden meiner Meinung nach nur einige Lösungen empfohlen:

  • Um Daten weiterzuleiten:
    • Überschreiben Sie die prepare(for:sender:)-Methode von UIViewController, wenn Sie ein Storyboard und Segmente verwenden
    • durchführen von Daten durch einen Initialisierer oder durch Eigenschaften, wenn View-Controller-Übergänge durch Code ausgeführt werden
  • Daten rückwärts weitergeben
    • aktualisieren Sie den gemeinsamen Status der App (den Sie mit einer der oben genannten Methoden zwischen View-Controllern weiterleiten können).
    • delegierung verwenden
    • verwenden Sie ein Abwicklungssegment

Lösungen, die ich empfehle, NICHT zu verwenden:

  • Verweisen auf den vorherigen Controller direkt, anstatt Delegierung zu verwenden
  • Daten über ein Singleton gemeinsam nutzen
  • Daten durch den App-Delegaten übergeben
  • Freigeben von Daten über die Benutzervorgaben
  • Weitergabe von Daten durch Benachrichtigungen

Obwohl diese Lösungen kurzfristig funktionieren, führen sie zu viele Abhängigkeiten ein, die die Architektur der App beeinträchtigen und später zu mehr Problemen führen werden.

Für Interessierte habe ich einige Artikel geschrieben, die sich eingehender mit diesen Punkten befassen und die verschiedenen Nachteile hervorheben:

5

Es gibt 3 Typen, um Daten von einem ViewController an einen anderen zu übergeben ViewController.

  1. Programmatisch
  2. Übergang
  3. UserDefaults

Demo-Projektlink hier - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

Programmatisch enter image description here

Segue enter image description here

UserDefaults enter image description here

Demo-Projektlink hier - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

4
Kamani Jasmin

Swift 5

Die Antwort von Matt Price ist für die Weitergabe von Daten völlig in Ordnung, aber ich werde sie in der neuesten Swift-Version neu schreiben, da ich glaube, dass neue Programmierer es aufgrund der neuen Syntax und Methoden/Frameworks als schwierig empfinden, da sich der ursprüngliche Beitrag in Objective befindet -C.

Es gibt mehrere Optionen zum Übergeben von Daten zwischen Ansichts-Controllern.

  1. Verwenden von Navigation Controller Push
  2. Segue verwenden
  3. Delegieren verwenden
  4. Verwenden von Notification Observer
  5. Block verwenden

Ich werde seine Logik in Swift mit dem neuesten iOS Framework umschreiben


Daten über den Navigationscontroller übertragen Drücken Sie : Von ViewControllerA zu ViewControllerB

Schritt 1. Variable in ViewControllerB deklarieren

var isSomethingEnabled = false

Schritt 2. Variable in ViewControllerB 'ViewDidLoad-Methode drucken

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

Schritt 3. In ViewControllerA Übergeben Sie Daten, während Sie den Navigationscontroller durchlaufen

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

Hier ist der vollständige Code für:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation Push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Daten durch Segue leiten : von ViewControllerA zu ViewControllerB

Schritt 1. Erstelle einen Übergang von ViewControllerA zu ViewControllerB und gib Identifier = showDetailSegue im Storyboard ein, wie unten gezeigt

enter image description here

Schritt 2. In ViewControllerB Deklarieren Sie eine funktionsfähige Datei mit dem Namen isSomethingEnabled und geben Sie ihren Wert aus.

Schritt 3. In ViewControllerA übergeben Sie den Wert von isSomethingEnabled, während Sie Segue übergeben

Hier ist der vollständige Code für:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Daten durch Delegaten übergeben : von ViewControllerB zu ViewControllerA

Schritt 1. Protokoll deklarierenViewControllerBDelegatein der ViewControllerB-Datei, jedoch außerhalb der Klasse

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

Schritt 2. Delegate-Variableninstanz in ViewControllerB deklarieren

var delegate: ViewControllerBDelegate?

Schritt 3. Daten für den Delegaten in der viewDidLoad-Methode von ViewControllerB senden

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

Schritt 4. Bestätigen Sie ViewControllerBDelegate in ViewControllerA

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

Schritt 5. Bestätigen Sie, dass Sie delegieren in ViewControllerA implementieren

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

Schritt 6. Implementieren Sie die Delegate-Methode zum Empfangen von Daten in ViewControllerA

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

Hier ist der vollständige Code für:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

Daten durch Notification Observer übergeben : Von ViewControllerB zu ViewControllerA

Schritt 1. Daten in Notification Observer in ViewControllerB festlegen und veröffentlichen

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

Schritt 2. Fügen Sie Notification Observer in ViewControllerA hinzu

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Schritt 3. Empfangen Sie den Benachrichtigungsdatenwert in ViewControllerA

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

Hier ist der vollständige Code für:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

Daten durch Block übergeben : von ViewControllerB zu ViewControllerA

Schritt 1. Deklarieren Sie den Block in ViewControllerB

var permissionCompletionBlock: ((Bool) -> ())? = {_ in}

Schritt 2. Setzen Sie die Daten in ViewControllerB in den Block

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

Schritt 3. Blockdaten in ViewControllerA empfangen

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

Hier ist der vollständige Code für:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

Eine vollständige Beispielanwendung finden Sie auf meinem GitHub. Bitte lassen Sie mich wissen, wenn Sie Fragen dazu haben.

3
swiftBoy

Dies ist ein wirklich tolles Tutorial für jeden, der es will. Hier ist der Beispielcode:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}
3

VERWENDEN VON NOTIFICATION CENTER

Für Swift 3

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }

Für Swift 4

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 @objc func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }
3
Sachin Rasane

um die Daten von einem VC an einen anderen zu senden, verwenden Sie diesen einfachen Ansatz:

YourNextVC *nxtScr = (YourNextVC*)[self.storyboard  instantiateViewControllerWithIdentifier:@"YourNextVC"];//Set this identifier from your storyboard

nxtScr.comingFrom = @"PreviousScreen"l
[self.navigationController nxtScr animated:YES];
2
Dalvik

nun, wir haben nur wenige Möglichkeiten, mit Delegierten-Systemen oder StoryboardSegue zu arbeiten 

1- As working with setter and getter method like in viewController.h
   @property (retain, nonatomic) NSString *str;
   now, in viewController.m
   @synthesize str;


   here i have pdf url and segue to another viewController like this and pdfObject is my pdfModel basicilly is NSOBJECT class.  

   str =[NSString stringWithFormat:@"%@",pdfObject.objPath];
NSLog(@"pdfUrl :***: %@ :***:",pdfUrl);

[self performSegueWithIdentifier:@"programPDFViewController_segue" sender:self];

pragma mark - Navigation

  // In a storyboard-based application, you will often want to do a little preparation before navigation

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

    if ([[segue identifier] isEqualToString:@"programPDFViewController_segue"]){
    programPDFViewController *pdfVC = [segue destinationViewController];
    [pdfVC setRecievedPdfUrl:str];

   }
 }

Nun habe ich erfolgreich meine PDF-URL-Zeichenfolge und andere ViewController erhalten und diese Zeichenfolge in Webview verwendet ... 

2- Bei der Arbeit mit Delegaten wie diesem habe ich eine NSObject-Klasse von Dienstprogrammen, die meine Methoden dateFormatter, sharedInstance, EscapeWhiteSpaceCharacters, convertImageToGrayScale und weitere Methoden enthält, mit denen ich nun in utilities.h gearbeitet habe

in diesem Fall müssen Sie keine Variablen erstellen, wenn Sie Ihre Daten in einem anderen View-Controller einmal in einem anderen View-Controller analysieren müssen. und wieder verwendet

  @interface Utilities : NSObject

  Utilities.h
 +(Utilities*)sharedInstance;

 @property(nonatomic,retain)NSString* strUrl;

jetzt in utilities.m

   @implementation utilities


  +(utilities*)sharedInstance
  {
  static utilities* sharedObj = nil;
  if (sharedObj == nil) {
    sharedObj = [[utilities alloc] init];
    }
   return sharedObj;
  }

now its done come to your firstViewController.m and call delegate

NSString*str =[NSString stringWithFormat:@"%@",pdfObject.objPath];

[Connection sharedInstance].strUrl=nil;
[Connection sharedInstance].strUrl=str;

 Now go to you secondViewController.m directly use it without creating variable 

 in viewwillapear what i did

 -(void)viewWillAppear:(BOOL)animated{
     [super viewWillAppear:YES];

   [self webViewMethod:[Connection sharedInstance].strUrl];

 }


 -(void)WebViewMethod:(NSString)Url{

 // working with webview enjoy coding :D

 }

diese Delegiertenarbeit ist zuverlässig mit der Speicherverwaltung 

2
Nayab Khan

Ich empfehle Blöcke/Verschlüsse und benutzerdefinierte Konstruktoren.

Angenommen, Sie müssen die Zeichenfolge von FirstViewController an SecondViewController übergeben.

Ihr erster View Controller. 

class FirstViewController : UIViewController {

    func moveToViewControllerB() {

        let second_screen = SecondViewController.screen(string: "DATA TO PASS", call_back: {
            [weak self] (updated_data) in
            ///This closure will be called by second view controller when it updates something
        })
        self.navigationController?.pushViewController(second_screen, animated: true)
    }


}

Ihr zweiter View Controller

class SecondViewController : UIViewController {

    var incoming_string : String?
    var call_back : ((String) -> Void)?

    class func screen(string: String?, call_back : ((String) -> Void)?) -> SecondViewController {

        let me = SecondViewController(nibName: String(describing: self), bundle: Bundle.main);
        me.incoming_string = string
        me.call_back = call_back
        return me
    }

    // Suppose its called when you have to update FirstViewController with new data.
    func updatedSomething() {

        //Executing block that is implemented/assigned by the FirstViewController.
        self.call_back?("UPDATED DATA")
    }

}
1
Umair

Sie können Push-Segue vom Quell-Viewcontroller zum Ziel-Viewcontroller erstellen und den Bezeichnernamen wie folgt angeben .  enter image description here

Sie müssen dies mit didselectRowAt durchführen.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "segue", sender: self)
}

Sie können das Array des ausgewählten Elements mit der folgenden Funktion übergeben.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    print(indexNumber!)
    let VC = segue.destination as! AddTransactionVC
   VC.val = CategoryData[indexNumber!] . //You can pass here entire array instead of array element.

}

Und Sie müssen den Wert in viewdidload des Ziel-Viewcontrollers prüfen und dann in der Datenbank speichern.

override func viewDidLoad{
 if val != ""{
        btnSelectCategory.setTitle(val, for: .normal)
    }
}
1
Parth Barot

Ich bevorzuge es, es ohne Delegierte und Abteilungen zu machen. Dies kann mit benutzerdefiniertem Init oder durch Festlegen optionaler Werte erfolgen.

1. Benutzerdefinierte init

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB(string: "Blabla", completionClosure: { success in
      print(success)
    })
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  private let completionClosure: ((Bool) -> Void)
  init(string: String, completionClosure: ((Bool) -> Void)) {
    self.completionClosure = completionClosure
    super.init(nibName: nil, bundle: nil)
    title = string
  }

  func finishWork() {
    completionClosure()
  }
}

2. Optionale Variablen

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB()
    viewController.string = "Blabla"
    viewController.completionClosure = { success in
      print(success)
    }
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  var string: String? {
    didSet {
      title = string
    }
  }
  var completionClosure: ((Bool) -> Void)?

  func finishWork() {
    completionClosure?()
  }
}
1

Eine Methode von Apple, dies zu tun, ist die Verwendung von Segues . Sie müssen die Funktion prepareForSegue () verwenden

Es gibt viele tolle Tutorials, hier ist eines: https://www.iphonelife.com/content/unleash-your-inner-app-developer-part-21-passing-data-between-controller

Lesen Sie auch die Apple-Dokumente zur Verwendung von Segues: https://developer.Apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html

1
tmac_balla

Einfacher geht es hier nicht.

Verwenden Sie einfach eine globale Variable. Deklarieren Sie das Objekt oder die Variable, die für die Übergabe an die nächste Klasse erforderlich sind.

Zum Beispiel haben wir 2 Klassen - classA und classB.

In classA enthält normalerweise:

#import "classA.h"

@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

und classB enthält:

#import "classB.h"

@interface classB()

@end

@implementation classB

-(void)viewWillLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

Importieren Sie nun die zweite Klasse classB nach classA

#import "classA.h"
#import "classB.h"  //---import classB to classA.
@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

Jetzt haben wir eine Brücke, über die wir zur zweiten Klasse classB gehen können. Um eine Variable oder ein Objekt als global zu deklarieren, deklarieren Sie es in der .m-Datei der ersten Klasse wie folgt

Im classA.h

#import "classA.h"
#import "classB.h"
@interface classA()

@end
NSString *temp;  //----declare any object/variable as global.
@implementation classA

-(void)viewDidLoad
{
    ...
    [email protected]"Hello";
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

Hier ist das Objekt temp ein globales Objekt der Klasse NSString für den Zugriff auf das globale Objekt oder die globale Variable in einer beliebigen Klasse, deklarieren Sie einfach das Objekt oder die Variable in der zweiten Klasse neu. Z.B. unten angegeben:

Im classB.m

#import "classB.h"

@interface classB()

@end
extern NSString *temp;  //----use `extern` keyword for using the global object/variable in classB that was declared in classA.
@implementation classB

-(void)viewDidLoad
{
    ...
    LabeL.text=temp;
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

Jetzt kann die zweite Klasse auf den Wert zugreifen. Einfach! .. Diese Methode kann für eine beliebige Anzahl von Klassen angewendet werden.

Anmerkung:

Sie sollten die .h-Datei der zweiten Klasse in die erste Klasse importieren. Es ist jedoch nicht erforderlich, die .h-Datei der ersten Klasse in die zweite Klasse zu importieren.

Erinnern Sie sich an die Brücke, wenn es eine Brücke gibt, sollte sie auf beiden Seiten gehen können.

Ich denke, das wird helfen. Es hat mir geholfen, als ich in der gleichen Situation war.

0
soorej babu

Sie müssen beim Erstellen von Apps für iOS immer das MVC-Konzept beachten. Es gibt zwei Szenarien, in denen Sie Daten von einem ViewController an einen anderen übergeben möchten:

  1. Wenn sich in der Hierarchie ein "A" ViewContoller befindet und Sie einige Daten an "B" senden möchten, ist dies der next viewcontroller. In diesem Fall müssen Sie Segue verwenden. Legen Sie einfach einen Bezeichner für das Segment fest und schreiben Sie dann im VC "A" den folgenden Code:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "A to B segue identifier" {
            let bViewController = segue.destination as! UIDocumentBrowserViewController
            bViewController.data = someData
        }
    }
    
  2. Wenn es eine A gibt, die B als modal (oder eingebettet) auf sich geöffnet hat. Der B viewcontroller sollte jetzt blind sein, was sein übergeordnetes Element betrifft. Die beste Methode, Daten an A zurückzusenden, ist die Verwendung von Delegation. Erstellen Sie ein Delegatenprotokoll im B viewcontroller und eine delegate-Eigenschaft. Also wird B an ihren Delegierten berichten (Daten zurücksenden). Im A viewcontroller implementieren wir das Delegate-Protokoll des B viewcontroller und setzen self als delegate-Eigenschaft von B viewcontroller in der prepare(forSegue:)-Methode.

So sollte es richtig implementiert werden. Ich hoffe es hilft

0
Shahin