Passing Values from One View Controller to Another in Swift

Passing data between view controllers

This question seems to be very popular here on Stack Overflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.

Passing Data Forward

Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.

For this example, we will have ViewControllerA and ViewControllerB

To pass a BOOL value from ViewControllerA to ViewControllerB we would do the following.

  1. in ViewControllerB.h create a property for the BOOL

     @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. in ViewControllerA you need to tell it about ViewControllerB so use an

     #import "ViewControllerB.h"

Then where you want to load the view, for example, didSelectRowAtIndex or some IBAction, you need to set the property in ViewControllerB before you push it onto the navigation stack.

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

This will set isSomethingEnabled in ViewControllerB to BOOL value YES.

Passing Data Forward using Segues

If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called

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

So to pass a BOOL from ViewControllerA to ViewControllerB we would do the following:

  1. in ViewControllerB.h create a property for the BOOL

     @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. in ViewControllerA you need to tell it about ViewControllerB, so use an

     #import "ViewControllerB.h"
  3. Create the segue from ViewControllerA to ViewControllerB on the storyboard and give it an identifier. In this example we'll call it "showDetailSegue"

  4. Next, we need to add the method to ViewControllerA that is called when any segue is performed. Because of this we need to detect which segue was called and then do something. In our example, we will check for "showDetailSegue" and if that's performed, we will pass our BOOL value to ViewControllerB

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

If you have your views embedded in a navigation controller, you need to change the method above slightly to the following

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

This will set isSomethingEnabled in ViewControllerB to BOOL value YES.

Passing Data Back

To pass data back from ViewControllerB to ViewControllerA you need to use Protocols and Delegates or Blocks, the latter can be used as a loosely coupled mechanism for callbacks.

To do this we will make ViewControllerA a delegate of ViewControllerB. This allows ViewControllerB to send a message back to ViewControllerA enabling us to send data back.

For ViewControllerA to be a delegate of ViewControllerB it must conform to ViewControllerB's protocol which we have to specify. This tells ViewControllerA which methods it must implement.

  1. In ViewControllerB.h, below the #import, but above @interface you specify the protocol.

     @class ViewControllerB;

    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
  2. Next still in the ViewControllerB.h, you need to set up a delegate property and synthesize in ViewControllerB.m

     @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. In ViewControllerB we call a message on the delegate when we pop the view controller.

     NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. That's it for ViewControllerB. Now in ViewControllerA.h, tell ViewControllerA to import ViewControllerB and conform to its protocol.

     #import "ViewControllerB.h"

    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. In ViewControllerA.m implement the following method from our protocol

     - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
    NSLog(@"This was returned from ViewControllerB %@", item);
    }
  6. Before pushing viewControllerB to navigation stack we need to tell ViewControllerB that ViewControllerA is its delegate, otherwise we will get an error.

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


References

  1. Using Delegation to Communicate With Other View Controllers in the View Controller Programming Guide
  2. Delegate Pattern

NSNotification center

It's another way to pass data.

// Add an 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];

Passing Data back from one class to another (A class can be any controller, Network/session manager, UIView subclass or any other class)

Blocks are anonymous functions.

This example passes data from Controller B to Controller A

Define a block

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

Add block handler (listener)

Where you need a value (for example, you need your API response in ControllerA or you need ContorllerB data on A)

// In ContollerA.m

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

Go to Controller B

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

Fire block

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

Another Working Example for Blocks

Passing data between a ViewController to another ViewController with navigation controller Swift 5

If you are using segue, then add "segue_identifier" in storyboard and the in secondviewcontroller add:

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue_ identifier" {
let mainTab = segue.destination as! tabBarController
let nav = mainTab.viewControllers[0] as! UINavigationController
let vc = nav.viewControllers.first as! HomeViewController
vc.cid = cityId
}
}

Because your segue destination is UINavigationController, you need to send data to view controller like this

Swift 3 - Passing data between a View Controller and after that to another 2

Before calling presentViewController add :

nextViewController.name = yourTextField.text

You could also delete the segue call. That is redundant.

Here is an example that I've used in the past :

    @IBAction func doSegue(_ sender: UIButton) {
buttonTag = sender.tag

let storyboard = UIStoryboard (name: "Main", bundle: nil)
let resultVC = storyboard.instantiateViewController(withIdentifier: "ResultViewController")as! ResultViewController

// Communicate with new VC - These values are stored in the destination
// you can set any value stored in the destination VC here
resultVC.firstValue = buttonTag
resultVC.secondValue = randomOpponentValue()
self.navigationController?.pushViewController(resultVC, animated: true)
}

Passing values from one view controller to another in Swift

Here's a general solution with two assumptions. First, UserId is not a UILabel. Second, you meant to use view which was instantiated in the second line, instead of using secondViewController

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var view: Dashboard = self.storyboard?.instantiateViewControllerWithIdentifier("Dashboard") as Dashboard
view.userId = employeesId[indexPath.row]
self.navigationController?.pushViewController(view, animated: true)

}

Here's what Dashboard looks like:

class Dashboard: UIViewController {
var userId: String!
@IBOutlet var userIDLabel: UILabel!

override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
userIDLabel.text = UserId
}

...
}

Passing a variable result from one view controller to another non-view controller swift file

Generally from what you are describing this is simply passing your object between view controllers you are having. Assume having:

class LoginData {
var username: String?
}

Now your first view controller seems to be your entry point so it is the one that creates it for instance on "next" button pressed. Then this object should be passed to the new view controller:

@IBAction onNextPressed() {
let loginData = LoginData() // Create object
loginData.username = self.textField.text // Set data to it

let nextController = UIStoryboard(...) as! NextViewController // Generate new view controller
nextController.loginData = loginData // Assign login data
navigationController.push(... nextController ...) // Show controller
}

So then the next view controller should use this object:

class NextViewController: UIViewController {
var loginData: LoginData?

override func viewDidLoad() {
super.viewDidLoad()
self.label.text = loginData?.username
}

...

In some cases though (which seems like yours) it might make sense to preserve data globally. To do so all you need is a static variable. In your case I suggest you create a new object User.

class User {
static var current: User?

var loginData: LoginData?
}

Now here User only contains login data but there is also a placeholder to add an instance of a current user which may be used whenever inside the app.

Now for this case the first view controller does not need to pass the data to next view controller but rather set the current user:

@IBAction onNextPressed() {
let loginData = LoginData() // Create object
loginData.username = self.textField.text // Set data to it

let newUser = User() // Create a new user
newUser.loginData = loginData // Assign login data to it
User.current = newUser // Set current user

let nextController = UIStoryboard(...) // Generate new view controller
navigationController.push(... nextController ...) // Show controller
}

And the new view controller does not need a reference to login data:

class NextViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
self.label.text = User.current?.loginData?.username
}

...

This is great when you need to use these data all over the app so as you mentioned some url you can now call anywhere User.current?.serviceURL if you implement:

extension User {
var serviceURL: URL? {
guard let username = username else {
return nil
}
return URL(string: "https://some.pat/\(username)/resource_name")
}
}

I hope this clears a few things about passing data in Swift.

Passing data from one view controller to another

Make string variable in your AppDelegate Like

var Model_id = String()

AppDelegate

and where you are getting value of username and userid sends its value to AppDelegate. make AppDelgate object like below and same in destinationViewController

let appDelegate = UIApplication.shared.delegate as! AppDelegate

to pass value to app delegate variable

self.appDelegate. Model_id = "your Value"

SourceView from which data is to be passed

and get your values wherever you want to fetch like below

let appDelegate = UIApplication.shared.delegate as! AppDelegate
let string = appDelegate. Model_id as! String

Destination ViewController

Swift 3 pass data from one ViewController to another ViewController

One the simpler way to pass info from one VC to another is either through an initiliazer, or through a variable that you set before presenting the second VC.

Since you are new to this, try the variable approach for now, so if say, you're passing a string:

class LoggedInVCViewController : UIViewController {

var info : String? {
didSet {
if let newInfo = self.info {
//do what ever you need to do here
}
}
}

override viewDidLoad() {
super.viewDidLoad()

}

}

func presentLoggedInScreen(yourInfo: String) {
let stroyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loggedInVC:LoggedInVCViewController =
storyboard.instantiateViewController(withIdentifier: "loggedInVC") as!
LoggedInVCViewController
loggedInVC.info = yourInfo
self.present(loggedInVC, animated: true, completion: nil)
}

Mind you, you can always use any other king of variable Class for info. You also would program your VC to execute some methods inside of the get bracket of the property, populate some fields based on the content of info, load a specific UI etc.

Another usefull way is to go the initialization route, but unfortunately you cannot use it with Storyboard nibs (sad i know, but this post goes over this nicely), but it still usefull whenever you will feel comfortable enough to initialize and design VC's programmatically (which I would learn ASAP if were you).

You pass a variable in a custom intializer method for your VC:

class LoggedInVCViewController : UIViewController {

var info : Any? {
get {
if let this = self.info {
return this
} else {
return nil
}
} set {
if let new = newValue {
//
}
}
}

init(info: Any?) {
//This first line is key, it also calls viewDidLoad() internally, so don't re-write viewDidLoad() here!!
super.init(nibName: nil, bundle: nil)

if let newInfo = info {
//here we check info for whatever you pass to it
self.info = newInfo
}
}

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

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

So you would use is as:

func presentLoggedInScreen(yourInfo: String) {
let loggedInVC = LoggedInVCViewController(info: yourInfo)
self.present(loggedInVC, animated: true, completion: nil)
}

Obviously, as stated, this method cannot be used with Storyboards, but very usefull and, as I'm sure you can see, is much more compact.

I suggest you get familiar with Swift Properties of the docs, along with some blog tips such as this one. You can get pretty creative after a while.

For learning more programmatic approaches, i strongly recommend this YouTube channel: Let's Build That App, I personnaly haven't found a better reference point for programmatic approach Swift programming.

Don't hesitate to ask questions!

UPDATE

Your IBAction should look like this:

@IBAction func creatAccountPressed(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion: { user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
}

let userID = user!.uid
let userEmail: String = self.emailTextField.text!
let fullName: String = self.nameTextField.text!

self.ref.child("users").child(userID).setValue(["Email": userEmail, "Name": fullName])

self.userID1 = user!.uid as! String

print(self.userID1)

presentLoggedInScreen(yourInfo: self.userID1)

})

}
}

passing data between view controllers programmatically Swift

you need to follow some steps

step1

initially embed with your initial VC to navigation controller , for e.g

Now select the first controller in Storyboard and click on Editor > Embed in... > Navigation Controller.

Sample Image

step2

Now you have to link the second Controller in Storyboard with your new SecondViewController.swift file.

Select the yellow circle at the top of the controller, click on the Identify inspector panel icon on the right side of the XCode window, and type the name of your new .swift file in the Class and StoryboardID fields

for e.g

Sample Image

step3

Passing a String

Now select the other controller in Storyboard and add this variable right below the SecondViewController class declaration:

 class SecondViewController: UIViewController {

let secondLabel = UILabel()

var stringPassed = ""

Make the app assign the value of this variable to secondLabel with the following line of code in the viewDidLoad() method

step4

on your first VC , inside the button

func buttonTarget() {

let myVC = storyboard?.instantiateViewControllerWithIdentifier("SecondVC") as! SecondViewController
myVC.stringPassed = label.text!

navigationController?.pushViewController(myVC, animated: true)

}

finally you get the out put as

 func setupLabelSecond() {

secondLabel.frame = CGRect(x: 40, y: 80, width: 300, height: 60)

if let outputText = stringPassed
{
secondLabel.text = outputText
}else
{
secondLabel.text = "this is Second Page"
}
secondLabel.textColor = UIColor.yellow
secondLabel.font = UIFont.boldSystemFont(ofSize: 25)
secondLabel.textAlignment = .center
secondLabel.layer.borderWidth = 2
secondLabel.layer.borderColor = UIColor.yellow.cgColor
secondLabel.layer.cornerRadius = 5
view.addSubview(secondLabel)
}

for sample you can get the tutorial here

update for XIB

   func buttonTarget() {

var vcPass = SecondViewController(nibName: "SecondViewController", bundle: nil)
vcPass.stringPassed = label.text!
self.navigationController?.pushViewController(vcPass, animated: true)

}

update for without XIB and Storboard

change your appdelegate

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
// Override point for customization after application launch.

let navigation = UINavigationController(rootViewController: MainViewController())
self.window?.rootViewController = navigation
self.window?.makeKeyAndVisible()
return true
}

on your MainViewController

 func buttonTarget() {

var vcPass = SecondViewController()
vcPass.stringPassed = label.text!
self.navigationController?.pushViewController(vcPass, animated: true)

}

Passing a String

Now select the other controller in Storyboard and add this variable right below the SecondViewController class declaration:

 class SecondViewController: UIViewController {

let secondLabel = UILabel()

var stringPassed = ""

Make the app assign the value of this variable to secondLabel with the following line of code in the viewDidLoad() method

func setupLabelSecond() {

    secondLabel.frame = CGRect(x: 40, y: 80, width: 300, height: 60)

if let outputText = stringPassed
{
secondLabel.text = outputText
}else
{
secondLabel.text = "this is Second Page"
}
secondLabel.textColor = UIColor.yellow
secondLabel.font = UIFont.boldSystemFont(ofSize: 25)
secondLabel.textAlignment = .center
secondLabel.layer.borderWidth = 2
secondLabel.layer.borderColor = UIColor.yellow.cgColor
secondLabel.layer.cornerRadius = 5
view.addSubview(secondLabel)
}

How to pass data from First ViewController directly to the Third View Controller using segue?

assign storybordID to your controller for ex here i have assigned "HomeVC" (it would be greate if you assign class name and storybordid same)

  let objthirdController = self.storyboard?.instantiateViewController(withIdentifier: "thirdControllerStoerybordID") as! thirdControllerclassname
objthirdController.variable = self.variable
self.navigationController?.pushViewController(objthirdController, animated: true)

How to pass data from one view controller to another?

You can try this Solution for Data Transfer.

In FirstViewController.swift

let str = "Hello It's Done"
func callsecondViewController()
{
let controller = storyboard?.instantiateViewController(withIdentifier: "second") as! secondViewController
self.present(controller, animated: true, completion: nil)
}
func temp() -> NSString
{
return str as NSString
}

in SecondViewController.swift

var data = [NSString]()
override func viewDidLoad()
{
super.viewDidLoad()
let view = ViewController()
data = [view.temp()]
print(data)
}

and you get the output String as Hello It's Done



Related Topics



Leave a reply



Submit