tutorial - mvc swift ios




Übergeben von Daten zwischen View Controllern (20)

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.

Erstellen Sie das Storyboard-Layout im Interface Builder. Um den Übergang zu machen, klicken Sie einfach auf die Schaltfläche und ziehen Sie über den zweiten Ansicht-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

  • UITextField die Steckdosen für das 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 zurückzugeben, verwenden Sie ein Protokoll und einen Delegaten . Dieses Video ist ein sehr übersichtlicher Ablauf dieses Prozesses:

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

Erstellen Sie das Storyboard-Layout im Interface Builder. Um den Übergang zu machen, ziehen Sie einfach die Strg-Taste von der Schaltfläche zum zweiten Ansicht-Controller. Setzen Sie die showSecondViewController 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 unseres benutzerdefinierten DataEnteredDelegate Protokolls.

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)
    }
}

Beachten Sie, dass das protocol außerhalb der View Controller-Klasse liegt.

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

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 UITableViewController und ich habe mehrere Auswahlen aktiviert.

Meine Frage ist, wie übertrage ich die Daten von einer Ansicht zur anderen? Ich halte die Auswahlmöglichkeiten in der UITableView in einem Array, aber wie übertrage ich diese dann zurück zur vorherigen Dateneingabeformularansicht, damit sie zusammen mit den anderen Daten in Core Data gespeichert werden kann, wenn das Formular UITableView ?

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?


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.


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 Poster fragte auch nach Singletons und der Verwendung des AppDelegate . 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 1: Maximal zwei View Controller müssen Informationen austauschen. Siehe Diagramm eins.

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 Ansichtscontroller müssen die gleichen Informationen teilen. Siehe Diagramm zwei.

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 dürfen) oder bestehende Elemente zu bearbeiten (die aus dem Formular "Neues Element hinzufügen" zugelassen werden können) zum Bearbeiten).

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 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 Instanz ist, die während ihrer Lebensdauer existiert. 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 im Leben der Anwendung immer genau einen Application Delegate gibt , der global erreichbar 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


Es gibt mehrere Methoden zum Teilen von Daten.

  1. Sie können Daten immer mithilfe von NSUserDefaults . Legen Sie den Wert fest, den Sie für einen Schlüssel Ihrer Wahl freigeben möchten, und NSUserDefault Sie den Wert von NSUserDefault , der diesem Schlüssel im nächsten View-Controller zugeordnet ist.

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

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


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:

Verwenden Sie 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 "Return" -Button an den grünen Exit-Button (Unwind) des VCs. Jetzt haben Sie ein Segment, das "zurückgeht", so dass Sie die Eigenschaft destinationViewController in prepareForSegue von VC2 verwenden und jede Eigenschaft von VC1 ändern können, bevor es zurückgeht.

  • Eine andere Möglichkeit, Storyboards und Window (Exit) zu verwenden - Sie können die Methode verwenden, 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 sie in prepareForSegue überprüfen.

Hoffe, ich habe etwas zur Diskussion hinzugefügt.

:) Prost.


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 Blöcken oft starke und schwache Referenzen wie die here erläuterte verwalten muss


1. Create the instance of first View Controller in the second View Controller and make its property @property (nonatomic,assign) .

2. Assign the SecondviewController instance of this view controller.

2. When you finish the selection operation copy the array to first View Controller,When u unload the SecondView ,FirstView will hold the Array Data.

Hope This Helps.


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;

Create the property on next view controller .h and define getter and setter.

Add this property in NextVC.h on nextVC

@property (strong, nonatomic) NSString *indexNumber;

Hinzufügen

@synthesize indexNumber; in NextVC.m

And last

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

[email protected]"123";

[self.navigationController vc animated:YES];

Delegation is the only one solution to perform such operations when you are using .xib files however all answers described above are for storyboard for .xibs files you need to use delegation. that's only solution you can.

Another solution is use singleton class pattern initialize it once and use it in your entire app.


I have seen a lot of people over complicating this using the didSelectRowAtPath method. I am using Core Data in my example.

- (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 lines of code inside the method and you are done.


I know this is a beaten subject but for those looking to answer this question with a SWIFT slant and want a bare-bones example, here my go-to method for passing data if you are using a segue to get around.

It is similar to the above but without the buttons, labels and such. Just simply passing data from one view to the next.

Setup The Storyboard

There are three parts.

  1. The Sender
  2. The Segue
  3. The Receiver

This is a very simple view layout with a segue between them.

Here is the setup for the sender

Here is the setup for the receiver.

Lastly, the setup for the segue.

The View Controllers

We are keeping this simple so no buttons, not actions, we are simply moving data from the sender to the receiver when the application loads and then outputting the transmitted value to the console.

This page takes the initially loaded value and passes it along.

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

    }

}

This page just sends the value of the variable to the console when it loads. By this point our favorite movie should be in that variable.

//
//  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)")

    }



}

That is how you can tackle it if you want to use a segue and you don't have your pages under a navigation controller.

Once it is run it should switch to the receiver view automatically and pass the value from the sender to the receiver, displaying the value in the console.


I was searching this solution for long time, Atlast I found it. First of all declare all the objects in your SecondViewController.h file like

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

Now in your implementation file allocate the memory for those objects like this

- (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;
}

Now you have allocated the memory for Array and object. now you can fill that memory before pushing this ViewController

Go to your SecondViewController.h and write two methods

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

in implementation file you can implement the function

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

expecting that your CustomObject must have a setter function with it.

now your basic work is done. go to the place where you want to push the SecondViewController and do the following stuff

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

Take care for spelling mistakes.


If you want to pass data from one controller to other try this 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];
 }

If you want to send data from one to another viewController, here's a way to it:

Say we have viewControllers: viewControllerA and viewControllerB

Now 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 this is how you can pass data from viewControllerA to viewControllerB without setting any delegate. ;)


In my case I used a singleton class which can work as a global object allowing accesses to the data from almost everywhere in the app. First thing is to build a singleton class. Please refer to the page," What should my Objective-C singleton look like? " And what I did to make the object globally accessible was simply import it in appName_Prefix.pch which is for applying import statement in every classes. To access this object and to use, I simply implemented class method to return the shared instance, which contains its own variables


There are many answers to this questions offering many different ways to perform view controller communication that would indeed work, but I don't see anywhere mentioned which one are actually best to use and which ones to avoid.

In practice, in my opinion only a few solutions are recommended:

  • To pass data forward:
    • override the prepare(for:sender:) method of UIViewController when using a storyboard and segues
    • pass data through an initializer or through properties when performing view controller transitions thtough code
  • To pass data backwards
    • update the app shared state (which you can pass forward between view controllers with either one of the methods above)
    • use delegation
    • use an unwind segue

Solutions I recommend NOT to use:

  • Referencing the previous controller directly instead of using delegation
  • Sharing data through a singleton
  • Passing data through the app delegate
  • Sharing data through the user defaults
  • Passing data through notifications

These solutions, although working in the short term, introduce too many dependencies that will garble the architecture of the app and create more problems later.

For those interested, I wrote some articles that address these points more in depth and highlight the various drawbacks:


There are tons of ways to do this and it's important to pick the right one. Probably one of the biggest architectural decisions lies on how the model code will be shared or accessed throughout the app.

I wrote a blog post about this a while back: Sharing Model Code . Here's a brief summary:

Shared data

One approach is to share pointers to the model objects between view controllers.

  • Brute force iteration on view controllers (in Navigation or Tab Bar Controller) to set the data
  • Set data in prepareForSegue (if storyboards) or init (if programmatic)

Since prepare for segue is the most common here is an example:

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

Independent access

Another approach is to handle a screen full of data at a time and instead of coupling the view controllers to each other couple each view controller to single data source that they can get to independently.

The most common way I've seen this done is a singleton instance. So if your singleton object was DataAccess you could do the following in the viewDidLoad method of UIViewController:

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

There are addition tools that also help pass along data:

  • Key-Value Observing
  • NSNotification
  • Core Data
  • NSFetchedResultsController
  • Data Source

Core Data

The nice thing about Core Data is that it has inverse relationships. So if you want to just give a NotesViewController the notes object you can because it'll have an inverse relationship to something else like the notebook. If you need data on the notebook in the NotesViewController you can walk back up the object graph by doing the following:

let notebookName = note.notebook.name

Read more about this in my blog post: Sharing Model Code


This is not the way to do it, you should use delegates, I'll assume we have two view controllers ViewController1 and ViewController2 and this check thing is in the first one and when its state changes, you want to do something in ViewController2, to achieve that in the proper way, you should do the below:

Add a new file to your project (Objective-C Protocol) File -> New, now name it ViewController1Delegate or whatever you want and write these between the @interface and @end directives

@optional

- (void)checkStateDidChange:(BOOL)checked;

Now go to ViewController2.h and add

#import "ViewController1Delegate.h"

then change its definition to

@interface ViewController2: UIViewController<ViewController1Delegate>

Now go to ViewController2.m and inside the implementation add:

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

Now go to ViewController1.h and add the following property:

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

Now if you are creating ViewController1 inside ViewController2 after some event, then you should do it this way using NIB files:

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

Now you are all set, whenever you detect the event of check changed in ViewController1, all you have to do is the below

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

Please tell me if there's anything that's not clear of if I didn't understand your question properly.


You can save data in App delegate to access it across view controllers in your application. All you have to do is create a shared instance of app delegate

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

For Example

if you declare a NSArray object *arrayXYZ then you can access it in any view controller by appDelegate.arrayXYZ





uiviewcontroller