iOS | iPhone | Tutorial on How-To Pass Data Between Two View Controllers

Passing data from a Source View Controller to a Destination View Controller is easy once you know the basics. Connecting two View Controllers in IOS with a Segue and using the prepareForSegue method passing data from the source View Controller to the destination View Controller is a simple process but it is often misunderstood. This tutorial provides a simple example on how to do this.

The main ingredient to keep in mind when passing data is that you need to define an object of type id in the destination to receive the object (data) form the source view controller. You assign the data to be sent to the id object in the destination view controller and you use the description method in the destination view controller of the id object to obtain the data that was sent from the source view controller.

Let me demonstrate....

Create The Project

Create a Single View application project, adding a storyboard and ARC. Once the project is created, open the storyboard and add a second View Controller (drag and drop from Object Library) on the canvas of the storyboard (Figure 1).

Figure 1 - Create a Single View Application
Figure 1 - Create a Single View Application

Setup the UI

Add a UITextField and a UIButton to the first view controller and create an IBOutlet (Figure 2) and a IBAction (Figure 3) by opening the Assistant editor (icon that looks like a face) and Control + drag a connection from the object to the open header file.

Figure 2 - Create an IBOutlet for the UITextField
Figure 2 - Create an IBOutlet for the UITextField
Figure 3 - Create an IBAction for the UIButton
Figure 3 - Create an IBAction for the UIButton

Create a UIViewController subclass, like DestinationVC by adding a new file to the project (Figure 4). Add the your Custom UIViewController class to the second View Controller in the storyboard by selecting the second view controller and opening the Identity inspector and adding the name of the UIViewController class to the Custom Class field (Figure 5).

Figure 4 - Add a UIViewController for the Second View Controller
Figure 4 - Add a UIViewController for the Second View Controller
Figure 5 - Add the Custom UIViewController class to the Second View Controller
Figure 5 - Add the Custom UIViewController class to the Second View Controller

Next Add two UILabel objects on the second view controller and and an IBOutlet for the second UILabel as above (figure 6). While the header file is open add an id instance variable like infoRequest and add the property to the implementation file (Figure 7).

Figure 6 - Add a IBOutlet to the Second UILabel on the Second View Controller
Figure 6 - Add a IBOutlet to the Second UILabel on the Second View Controller
Figure 7 - Add the variable of type id To Be Use to Pass Data to the implementation file.
Figure 7 - Add the variable of type id To Be Use to Pass Data to the implementation file.

Next create a Segue by selecting the UIButton and drag a connection to the UILabel (The one with the IBOutlet) on the second view controller (Figure 08). In the Popover box select the Push Segue type (Figure 09). Now we have our Segue and the two view controllers are connected. One last step is to name our Segue. Select the Segue and open the Attributes inspector and enter a name in the Identity field (Figure 10).

Figure 8 - Add an IBOutlet to the Second View Controller
Figure 8 - Add an IBOutlet to the Second View Controller
Figure 9 - Select the Push Type Segue
Figure 9 - Select the Push Type Segue
Figure 10 - Name the Segue in the Identity inspector
Figure 10 - Name the Segue in the Identity inspector

Next add a Navigation View Controller to the canvas by selecting the first view controller and from the Editor menu in Xcode, select Embed In -> Navigation Controller (Figure 11).

Figure 11 - Add a Navigation View Controller to the First View Controller
Figure 11 - Add a Navigation View Controller to the First View Controller

Now our UI is complete (Figure 12). The next steps will add code to the first view controller to send the data from the UITextField and we will add some code to display that information in the UILabel in the second view controller.

Figure 12 - The Completed UI
Figure 12 - The Completed UI

Add Code to Send Data


Open the implementation file for the first view controller and add the UIViewController instance method prepareForSegue

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

In the method add the following code:


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:@"SendInfo"]) {
Destination *detailViewController = [segue destinationViewController];

NSLog(@"text : %@",self.CaptureInformation.text);
//This is the id infoRequest, which is a pointer to the object
//Look at the viewDidLoad in the Destination implementation.
detailViewController.infoRequest = self.CaptureInformation.text;
}
}


The first line of code checks to see which Segue is being called. This is a bit redundant since we only have one Segue for this example. Next create a destination view controller object. Since I called mine Destination, I will create an instance of my Destination class and define it as the destinationViewController as the target or destination of my Segue.

I'll add an optional NSLog to check to see if I am capturing my information correctly. Then I'll assign the value of my UITextField, CaptureInformation, to the id object, infoRequest, that is defined in my destination view controller: detailViewController. This is the important part. This is how data gets transferred, by assigning the desired value to the id object of the destination view controller.

Add Code to Display Data


We are almost done. Now you need to add code to the destination view controller to actually display the information that you sent in the UILabel. Open the implementation file of the destination view controller and add the following code to the viewDidLoad method:

- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"received info %@", [self.infoRequest description]);

//Receive id (object) from klViewController and display in label
self.ReceiveInfo.text = [self.infoRequest description];

}

I added a NSLog again to see if I received the information correctly by accessing the description property of my id object, infoRequest. The important line of code is the last one where I assign the value from the description property of my id object, infoRequest, to my UILabel, ReceiveInfo.

The Output


That is it. The magic happens with all important id object. This is mechanism that you will use for any data transfer from a source view controller to a destination view controller. It is important to note that this is a one way transfer. If you need to send back data from the destination view controller to the source, you will need to define a Delegate (which is beyond the scope of this tutorial).

Run the app and enter some information in the UITextField ( I didn’t add any code to dismiss the keyboard, but you can find detailed information on this tutorial on dismissing a keyboard) and press the Send Information button. Your text will appear in the Destination View Controller UILabel once the view controller pushed to the top of the stack (Figure 13).

Figure 13 - The Running App
Figure 13 - The Running App

More by this Author


Comments 43 comments

mikeydcarroll67 4 years ago

As usual good hub! I've been bookmarking them for future use!


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

:). A lot of people have been asking for one like this. Passing data from one VC to the next seems to be misunderstood a lot. So I hope many programmers can benefit form it and wrok through their roadblock. BTW how is your app coming along?

K


mikeydcarroll67 4 years ago

It's been very slow and a few errors here and there. I'm figuring it out as I go. I hope to have it done within a couple weeks.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Cool....


Robert 4 years ago

Why not just make an extern NSString variable deceleration and set equal to the input in one and set the output in the other to the same NSString?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Using an extern, although it does create a variable with global visibility, you get an EXC_BAD_ACCESS error with ARC. The extern works fine when defining a constant.


Robert 4 years ago

Really. I have not tried with ARC. I have used this method without ARC with no issues. Maybe I was not clear. I define an NSString called passData in first viewController as follows:

NSString *passData = @"";

somewhere in the first viewController I put the statement:

passData = input.text;

In the second viewController I set extern NSString passData as follows:

extern NSString *passData;

somewhere in the second viewController I put the statement:

output.text = passData;

Are you saying this will not work with ARC?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I haven't tried it. Let me test....


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I have tried as you stated in your comment....

I am getting linkage errors...

=============================

Ld /Users/klanguedoc/Library/Developer/Xcode/DerivedData/externVar-..../Build/Products/Debug-iphonesimulator/externVar.app/externVar normal i386

cd /Users/klanguedoc/git/externVar

setenv MACOSX_DEPLOYMENT_TARGET 10.6

setenv PATH "/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"

/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/clang -arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -L/Users/klanguedoc/Library/Developer/Xcode/DerivedData/externVar-.../Build/Products/Debug-iphonesimulator -F/Users/klanguedoc/Library/Developer/Xcode/DerivedData/externVar-..../Build/Products/Debug-iphonesimulator -filelist /Users/klanguedoc/Library/Developer/Xcode/DerivedData/externVar-.../Build/Intermediates/externVar.build/Debug-iphonesimulator/externVar.build/Objects-normal/i386/externVar.LinkFileList -mmacosx-version-min=10.6 -Xlinker -objc_abi_version -Xlinker 2 -fobjc-arc -Xlinker -no_implicit_dylibs -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -framework UIKit -framework Foundation -framework CoreGraphics -o /Users/klanguedoc/Library/Developer/Xcode/DerivedData/externVar-..../Build/Products/Debug-iphonesimulator/externVar.app/externVar

Undefined symbols for architecture i386:

"_passData", referenced from:

-[otherViewController viewDidLoad] in otherViewController.o

ld: symbol(s) not found for architecture i386

clang: error: linker command failed with exit code 1 (use -v to see invocation)


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi Robert

As a test, I have tried your suggestion without ARC and it works perfectly. So my solution is the way to go with ARC, otherwise extern, as you said, is great to pass data between view controllers.

Extern is indeed the keyword to use for variables with a global scope. This keyword also works and I have used with C, C#....

Thanks for sharing...

Kevin


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

Although i found this quite helpful, my main problem remains.

I have a view where the users chooses what they want to include in a search.

There is a series of switches which when set will create a NSString which i will pass into a tableviewcontroller once viewdidunload (there is a tab navigation). i can understand how the above sends data if a button is pushed but i can't seem to pass the variable or make its data accessible. i've googled and searched through hundreds of forum posts but they either all seem overly complicated or so dated that its hard to follow.

i just need a NSString 'VenueSearchField' set in view 'CriteriaViewController' to have its data accessible in another view 'ListedViewController', which uses that variable in a SQLite query.

I've looked up global variables but they seem to be shunned and methods found don't seem to work and had a look into NSUserDefaults which did the trick but once i set it, it doesn't seem to be resettable (is it not mutable??). Using Plists and singleton seem overly complicated. The closest i seem to find is setting a property in an NSObject class which i can set but haven't figured out how to extract the data in the second view. I am looking into setting it to the appDelegate but seriously am i missing something? surely there is a simple way of setting a variable and then using that variable in another view without the awful stigma seemingly associated with globals??


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

just as i wrote the above, my page refreshed and i noticed your postings about extern global variables. How can i get around the ARC issue if its so embedded in my coding so far. do i need to sacrifice one for the other?


Robert 4 years ago

Another method too be data between vc's is to write to a file in one bc and read from the file in the other bc. Maybe this could solve your problem?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Yes. If you are using extern in existing apps, pre IOS 5, you could use file, or SQLite and access the same database or even Core Data, but if your app has externs, you will probably run into linkage problems as noted above.


Robert 4 years ago

No need for extern with file, so it should work with iOS 5.


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

i got it working using plist's, thanx for your feed back.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Sorry kriszsomogy, I overlooked your previous comment and I am kind a a lot lost as to where you are in the discussion. You said you have figure out how to pass variable globally using the plist? If so great. I am happy :). I was also thinking about the use of the AppDelegate or using a file. Anyway, please let me know if I can provide some input.

K


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

I have a series of switches grouped in various ways which when combined then create a search query which displays data in a table view, but when i return to the setting's screen where all the switches are, they all return to their off state.

i tried setting a plist item for each of the switch settings which passes and returns fine.

My problem is that when i try to use the returned value to set the switches, it just doesn't work in an 'if' statement

i can take the value and it works fine when i pass it to a label.text

but if i try it in an if statement it doesn't recognise the data.

I figured that the data type might be coming back an 'id' type and tried 'type def'ing it as a nsstring but it still doesn't work

here is the code:

CocktailLoungesSaved = [Saved objectForKey:@"CocktailSwitchSaved"];

CocktailSwitchInts = [NSString stringWithFormat: CocktailLoungesSaved];

label1.text = CocktailSwitchInts;

if (CocktailSwitchInts == @"2")

{label2.text = @"1";

CocktailLoungesSwitch.on = TRUE;}

else {label2.text = @"2";

CocktailLoungesSwitch.on = FALSE;};

CocktailSwitchSaved comes back as 1 or 2 (or yes/no, set unset) no problems and label1. text changes but label2.text doesn't.

i've tried without line 2 and passing CocktailSwitchSaved (originally) but i suspect its something to do with the data type.

Any help would be great


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

Never mind, i've solved it...

I created an integer

NSInteger CocktailSavedInt = [ CocktailLoungesSaved intValue ];

and passed that in.

Originally i had been working with strings, but these integers will work just fine

that took half my day to unravel d'oh...

Thanx anyway


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Yay!!, the joys of programming. Sorry I didn't get back fast enough. I am having a hectic. I liked your idea of using plist custom keys. I am glad you are got it working.


kriszsomogyi 4 years ago

My series of switches has turned from a series of 'if' statements into a monster of 8000 lines of code where 500 would have probably done it using lists/arrays and for/while loops.

I worked out the passing of data with plists but learnt the hard way that 'id' data types can be tricky and that when debugging when using plists that flushing the settings could have saved a lot of time. Typo's have also become my mortal enemy (especially when I have auto complete into the wrong variable). Which is a terrible problem when you have to scour through 6000-7000 lines of code to realize you passed the wrong variable in dozens of places. Got some good practice in at least. Without turning this into my personal blog, I just had to get that off my chest to anyone who'd understand lol


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I am glad to hear from you. It sounds like a bit of a nightmare lol. It is crazy how we can eyeball some code for so long that it becomes a blur while the issue might be staring us right in the face.

Another way to go with sharing data is with resource files. i will write up a short tut on using those.

K


jaiii 4 years ago

thanks for this! saved my life for a project!!


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

You are very welcome. Glad to help.


Steve 4 years ago

Really clear tutorial. It helped a lot

Two points:

1. You need to import DestinationVC into the source ViewController to use the prepareForSegue

2. The IBAction sendInformation doesn't seem to be necessary for this. The segue takes place without it, and the method implementation is empty.

Please correct me if I'm wrong or if there's a reason I'm not aware of yet.

Thanks again, Steve


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

You are correct that you need to import the DestinationVC as is the case in any app where you need to access a class. for the sendInformation, you don't really need an IBAction unless you want to do some other processing beforehand. But it is necessary to create a delegate for the sendinformation button otherwise the segue and navigation controller won't work.

thanks for the feedback.


kriszsomogyi profile image

kriszsomogyi 4 years ago from Ashgrove, QLD

I've come across a small problem that maybe I should know but it's got me frustrated...

It's also a little off this pages topic but either I've figured it out or someone has given me a tip to sort it out whenever I've been stuck, so any help would be great.

I am trying to pass a variable into the name of a label and/or another variable.

I have database of hundreds of venues with dozens of properties (details) which I want to display in various combinations. For example, I have say venue 1-500 with 50 properties each which I can sort through in a table view pretty easily but if I want to group 10-20 venues on one screen of an iPad scroll view then I have to create 20 labels for 15 properties on 10 different pages (various groupings), which each need to be declared in the header file, synthesized and then linked to the database. I have to do this quite a bit more and there must be an easier way...?

Could I do a 'for loop' and pass a variable into the name of a label?

I.e.

for ( int num =0;

num greater than symbol thebars.count;

num++)

{

Guides *barguide(num) = [self.BarGuideList objectAtIndex:num];

namelabel(num).text = barguide.venuename;

}

(num) is where I'd like to pass the variable into so that it goes through the array and it sets each labels output to the corresponding data in the database.

It all works fine if I just set each label individually. But I had a similar issue in another element of my app and it snowballed into a 7000 lines of code. I've slowly unravelled that one using arrays and plists but if could only figure out how to pass in the variable into the name of the label then it could save me thousands of lines of code. Is it possible to do so when I declare the label in the header file or when I synthesize it?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Off the top of my head and I understood correctly, if you built the TableView programmatically, you could possibly access the label properties in the table. I have never tried.


Tarben 4 years ago

the object (data) form the source view controller.

FROM


Kim 4 years ago

I got three NSArray named a,b,c and another NSMutable Array named na. The 3 arrays contains elements imagename.image. When the button is taped the 3 arrays are merged to the mutable array na. Again the array get split. This process is repeated and after the third tap the 10th element of na should be displayed on another view controller.I have set a counter j. i need the steps when j==3. Can you help me. I am new to xcode. Thanks


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

1- First you would need to setup your view controllers with a segue

2- In your first view controller implement the prepareForSegue method, like this

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

{

if ([[segue identifier] isEqualToString:@"showAlternate"]) {

[[segue destinationViewController] setDelegate:self];

}

}

3-In the method you would add your logic to check the number of times the button was tapped, like

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

{

int j=0;

if ([[segue identifier] isEqualToString:@"showAlternate"]) {

//you will to cast your NSMutableArray to a NSArray to be able to use the count property

if(j==3)

{

for(int i=0; i "less than" (NSArray *)mutableArray.count; i++)

{

if(i==10)

{

[[segue destinationViewController] setDelegate:self];

}

}

}

}

}

===============================================================

Note: replace the "less than" with the actual symbol since this comment field doesn't allow symbols that ressemble html elements.

===============================================================

This assumes of course you have setup your view controllers with a segue and delegate. I haven't tested this code so there will probably need tweaking to get the final working version.

I can create a tutorial on this if you have trouble but it will take me a day or two to get it all done.

Let me know

Kevin


Ahmet 4 years ago

Thanks a lot...


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Glad to help, if I can


Thom 4 years ago

Great tutorial, I was able to complete the app without any problems. I also added the ability to dismiss the keyboard. Following your tutorial made the process very easy. One question, what additional code is needed to make the passing of data between the view controllers a two-way process? I would also like to send data from the destination controller back to the source controller. Many thanks!!!


Patrick Lanneau profile image

Patrick Lanneau 4 years ago

It's a good and easy method to transfer datas between two view for iphone or for iPad.

But with an iPad, we can use for segue a popover, and if we use popover, i can't transfer datas...

Somebody can explain a method for popover ?


Richard Moya profile image

Richard Moya 4 years ago from Madrid, Spain

Could you please share the project? I tried to make this tutorial but there is something that I know and I can not fault it.

If no matter what I could send mail to "setmoya@gmail.com"

thanks

regards


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Thom,

Thanks for the positive feedback, I always appreciate it. Please my explanation below to Patrick Lanneau. Basically you need to create and a protocol in the modal view controller and implemented it in the calling view controller. Then access the data using an id object.

Patrick Lanneau

First sorry for the late response. For popovers you can push data to the popover view controller using a segue. the segue must be set as modal and you need to set the dimensions of the view controller smaller than the normal size otherwise it will sit on top of the calling view controller. To return data from the popover back to the calling view controller, you will need to create a delegate (also called a protocol). Actual to create a delegate, you use the protocol directive.

I don't have the code right now, but I can put an example together in the next few days because I am working on a project right now and I have a deadline for Friday.

Richard Moya

I will send you the source code later when I get home, and I also apologize for my tardiness.

Kevin


Iva 4 years ago

Hallo Kevin,

your tutorials are really great!!!

I am already so long time trying to pass a different images with description from first view controller and second view controller to an array of UIImageViews placed in third view controller (in storyboard).

I can pass image through prepareForSeque to concrete UIImageView. But not that they are passed one after the other in third view controller.

Is it possible, that you make some tutorial? Or send only a sample code?

Thank you very much!!!

Iva


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hey Iva, you are starting to push the envelop :). I have code to send images to a second uiviewcontroller, but not a third. but i love a challenge. I could put some code together by next week if that is ok with you.


Iva 4 years ago

Kevin,

you are really unbelievable :) Thank you very much for your help... All of us, who are new in iOS development appreciate your tutorials, believe me... Thanks for your time!

I can for sure wait... The only problem what I have is to send this images to an array... Only image sending to a concrete place is no problem... But how to do it, that the images are coming one after the other as you choose them from the view controllers (img1,img3,img4, img2 - but when you choose them next time, they will be seen as img3,img2,img1,img4... - with description :)) and are shown in third view controller...

Thank you once again :)


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

You can add multiple images sequentially and or sporadically using the NSMutableArray as the name implies. It has an addObject method so you can load images easily and you can edit the array at runtime to add or remove elements as needed.

Thanks for the great complements


Behnaz 4 years ago

Hi,

I tried your code, however when I press the button in the first view controler it throws an exception (where DependentViews is my first view controller) :

DependentViews: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: DestinationViewController setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key ReceiveInfo.'


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

your destination controller is not properly defined

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working