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.
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
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:
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
, so use an#import "ViewControllerB.h"
Create the segue from
ViewControllerA
toViewControllerB
on the storyboard and give it an identifier. In this example we'll call it"showDetailSegue"
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 ourBOOL
value toViewControllerB
-(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.
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;
@endNext still in the
ViewControllerB.h
, you need to set up adelegate
property and synthesize inViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
In
ViewControllerB
we call a message on thedelegate
when we pop the view controller.NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];That's it for
ViewControllerB
. Now inViewControllerA.h
, tellViewControllerA
to importViewControllerB
and conform to its protocol.#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>In
ViewControllerA.m
implement the following method from our protocol- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@", item);
}Before pushing
viewControllerB
to navigation stack we need to tellViewControllerB
thatViewControllerA
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
- Using Delegation to Communicate With Other View Controllers in the View Controller Programming Guide
- 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
How to transfer data from one view controller to another
Remove these lines :
let vct = self.storyboard?.instantiateViewController(withIdentifier: "Home2")
self.present(vct!, animated: true, completion: nil)
You are already pushing the same viewController in navigationController.
Your final code should be :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
var (cellName) = myList[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: "Home2") as! ShopViewController
viewController.name = cellName
navigationController?.pushViewController(viewController, animated: true)
print("row\(indexPath.row)")
print("name: \(cellName)")
}
This should work only once you have set the viewController's identifier in storyboard. This is how you can do that :
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
Passing data from one view controller to another
Make string variable in your AppDelegate Like
var Model_id = String()
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"
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
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)
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)
})
}
}
how to pass data from one view controller to another and between the view controller there is a reveal view controller]
You can make use of userDefaults, eg in LoginViewController
save data to be used, as done below:
UserDefault.standard.setValue(name, forKey: "User_name")
UserDefault.standard.synchronize()
To use saved data on profile screen:
if let userName = UserDefault.standard.value(forKey: "User_name") as? String {
self.lblUserName.text = userName
}
Hope this helps out somehow.
Related Topics
What Privacy-Violating or Device-Changing Things How to Do on an Iphone
How to Parse This JSON in Swift
Scrollview and Keyboard in Swift
Making an Array of Integers in iOS
iOS Certificate Pinning with Swift and Nsurlsession
iOS Tesseract Ocr Image Preperation
"The Data Couldn't Be Read Because It Is Missing" Error When Decoding JSON in Swift
Detect If a Point Is Inside a Mkpolygon Overlay
How to Add Done Button on Keyboard on Top of Keyboard in iOS
iOS Simulator Display Scaled Incorrectly
Waiting for Asynchronous Function Call to Complete
How to Manage Sessions with Afnetworking
iOS Avplayer Trigger Streaming Is Out of Buffer
Obscure a Uitextfield Password