Sending Data With Segue With Swift

Pass data through segue

Swift works exactly the same way as Obj-C but is reworked in the new language. I don't have a lot of information from your post but let's give a name to each TableViewController to help with my explanation.

HomeTableViewController (this is the screenshot you have above)

PlayerTableViewController (this is the player screen you want to travel to)

With that said, in PlayerTableViewController you need to have a variable that will store the passed data. Just under your class declaration have something like this (if you intend to store the struct as a single object rather than the array:

class PlayerTableViewController: UITableViewController {

var programVar : Program?

//the rest of the class methods....

After that there are two ways you can send data to the new TableViewController.

1) Using prepareForSegue

At the bottom of HomeTableViewController you will use the prepareForSegue methods to pass the data. Here is an example of the code you'll use:

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

// Create a variable that you want to send
var newProgramVar = Program(category: "Some", name: "Text")

// Create a new variable to store the instance of PlayerTableViewController
let destinationVC = segue.destinationViewController as PlayerTableViewController
destinationVC.programVar = newProgramVar
}
}

Once PlayerTableViewController has loaded the variable will be already set and usable

2) Using didSelectRowAtIndexPath

If specific data needs to be sent based on which cell is selected you can use didSelectRowAtIndexPath. For this to work, you need to give your segue a name in the storyboard view (let me know if you need to know how to do this too).

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

// Create a variable that you want to send based on the destination view controller
// You can get a reference to the data by using indexPath shown below
let selectedProgram = programy[indexPath.row]

// Create an instance of PlayerTableViewController and pass the variable
let destinationVC = PlayerTableViewController()
destinationVC.programVar = selectedProgram

// Let's assume that the segue name is called playerSegue
// This will perform the segue and pre-load the variable for you to use
destinationVC.performSegueWithIdentifier("playerSegue", sender: self)
}

Let me know if you need any other info on this

passing tapped cell data to another view via segue in Swift

Make sure that you have created your segue from the view controller object in the storyboard and not the cell; if you create the segue from the cell, then the segue will fire before didSelectRowAt is called.

Once you have set the segue correctly, you can use the sender parameter to avoid the use of the detailToSend property:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

var detailToSend: SingleRepository
if filteredResult.count > 0 {
detailToSend = filteredResult[indexPath.row]
} else {
detailToSend = finalArrayUnwrapped[indexPath.row]
}
performSegue(withIdentifier: "showDetailSegue", sender: detailToSend)
}


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? DetailViewController, let detailToSend = sender as? SingleRepository {
vc.detail = detailToSend
}
}

Passing Data between view Controllers Using a segue from a view embedded in a navigation controller to a tabbarcontroller

This is my view controller where you can check that I am sending 5 to tabbar first viewcontroller:

   class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.performSegue(withIdentifier: "segueIdentifier", sender: self)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let barViewControllers = segue.destination as! UITabBarController
let destinationNv = barViewControllers.viewControllers?[0] as! UINavigationController
let destinationViewController = destinationNv.viewControllers[0] as! FirstViewController
destinationViewController.currentBalance = 5
}
}

Now You can check my firstview controller where you can check that what value we are getting.

class FirstViewController: UIViewController {

var currentBalance = 0
override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
print(currentBalance)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

Now, You can check my console and storyboard:
Sample Image

Sample Image

Prepare for segue function can't pass data to another VC Swift,

First of all rather than declaring an extra property or saving the value to UserDefaults you can pass the string in the sender parameter

let action = UIAlertAction(title: "Download", style: .default) { (action) in
guard let textField = alert.textFields?.first else {return}
self.performSegue(withIdentifier: "segAdd", sender: textField.text!)
}

Your way to determine the destination view controller is wrong. Ask the segue for the destination. And you can force downcast the type. The code must not crash if the segue is designed correctly.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segAdd" {
let destinationVC = segue.destination as! BrowserWebViewController
destinationVC.urlFromDownloads = sender as! String
print("The value of destinationVC?.urlFromDownloads is \(destinationVC.urlFromDownloads)")
}
}

Passing data with segue through navigationController

The destination view controller of the segue is the UINavigationController. You need to ask it for its top view controller to get to the real destination view controller:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showItemSegue" {
let navController = segue.destination as! UINavigationController
let detailController = navController.topViewController as! ShowItemViewController
detailController.currentId = nextId!
}
}

Passing data with segue from UITableView to UIViewController

From what I suspect, you have not programmatically pushed your segue.

Taking hint from here, did you push the segue from your didSelectRowAtIndexPath method?

Passing data to new ViewController through Segue

You define

var films: [Results]

and then call

performSegue(withIdentifier: "detailsSegue", sender: films)

and then cast

let filmCell = sender as? Results

which will not work since Results is not [Results], decide if you want an array of Results or just one.

Passing data on segue to view controller (Swift)

You can use a class which is common to all view controllers , and save your details to this common class variables.

  1. First create a new swift file called PartyDetails

    import Foundation

    class PartyDetails {

    class var sharedInstance: PartyDetails {
    struct Static {
    static var instance: PartyDetails?
    static var token: dispatch_once_t = 0
    }

    dispatch_once(&Static.token) {
    Static.instance = PartyDetails()
    }

    return Static.instance!
    }

    var partyName: String?
    var address: String?
    var city: String?
    var state: String?
    var zip: Int?

    }

  2. Then in ViewControllers A,B,C put this code

eg:-

class A: UIViewController{


let partyInfo = PartyDetails.sharedInstance

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

if segue.identifier == "Setup1Segue" {
let jobDetailViewController = segue.destinationViewController as! B

self.partyInfo.partyName = label1.text // save your info
self.partyInfo.address = label2.text // save your info

}
}

}
}

  1. Then In class D use like this,

    class D: UIViewController {

    var partyInfo = PartyDetails.sharedInstance

    override func viewDidLoad() {

    super.viewDidLoad()

    myLabel1.text = self.partyInfo.partyName
    myLabel2.text = self.partyInfo.address
    }
    }

Passing data between View Controllers using Segue

"Passing data to the destination Controller" when a segue is triggered will be achieved by overriding method prepareForSegue:sender:.

Generally, you pass data and NOT the source view controller, to the destination view controller. "data" may be a certain aspect of your application "model". It's an object like "User", or perhaps an array containing "User", etc.

The destination view controller shall not have any knowledge of the source view controller. That means, the destination view controller does not need to import the header of the source view controller.

On the other hand, the source view controller may have knowledge of the concrete class of the destination view controller or a base class of the destination view controller, and thus will import the header of the destination view controller.

See: Configuring the Destination Controller When a Segue is Triggered

If you need some sort of "communication protocol" between the source and the destination, you might employ Delegation to communicate with other view controllers. This involves the definition of a @protocol (e.g. having a method doneButton) and a property delegate which is defined in the destination view controller. The protocol should be defined in the header of the destination view controller, if it's specific to the destination view controller. Usually, you define tho protocol from the view point of the destination controller, and not from the requirements of the source controller.

The source view controller then creates a delegate (unless, it itself is it already) and sets the delegate of of the destination view controller. The destination view controller will send the delegate methods to the delegate, and the delegate handles it.

Now, passing "data" from a VC_A to VC_B should be straight forward. You should read a few examples which use prepareForSegue:sender:. For example, the destination view controller may have a property data which represents the thing it should display. The source view controller must set this property in prepareForSegue:sender:.

Passing data from VC_A over VC_B to VC_C should be straight forward as well.

Note: Each view controller may tailor (separate, modify, prepare, slice, transform, etc.) its data to make it a suitable data for the next view controller.


If VC_C needs data that is not available in its source view controller VC_B, then there are a couple of approaches to solve this. However, this is usually a sign of bad design.

You could have an application model, which is global. Suppose, your "application model" is an object of type Document. Suppose, at any time there is only one instance of that application model. Then, the model is a "Singleton", which could be accessed from anywhere in your app like so:

Document* document = [Document sharedDocument];

However, the preferred way to get an instance of a model is in the first view controller which requires access to it, in this case: VC_A.

Then, VC_A passes a Document instance to the next view controller VC_B. And VC_B passes the document object to VC_C.

You should read the official documentation "View Controller Programming Guide for iOS".


Example 1

Suppose, you have a list "Users". The list should be displayed in a table view controller, and there should also be a detail view, showing details of one User.

The table view controller will have a "data" property users:

In UsersTableViewController.h:

@interface UsersTableViewController : UIViewController
@property (nonatomic, readonly) NSArray* users;
@end

(Strictly, this user property doesn't need to be public. For example, if the table view internally obtains the list of users itself, there is not need to access it from outside.

The "users" array is the data of the table view which shall be displayed in rows. Each row shows a "summary" of a user.

More details of a user should be displayed in a detail view controller. The detail view controller's data is a single user of type User.

When the user tabs a certain row in the table view, the detail view controller will be displayed. Before it will be displayed, the table view controller must configure the detail view controller: the table view controller assigns the detail view controller's "data property" the current selected user. Thus, the detail view controller should have a public property user:

@interface UserViewController : UIViewController
@property (nonatomic) User* user;
@end

The table view controller configures the detail view controller in prepareForSegue:sender::

In UsersTableViewController.m

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) {
UserViewController* userViewController = [segue destinationViewController];
userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}

Example 2

The second example is more complex and uses "Delegation" as a means to establish a communication between controllers.

Caution:

This is not a complete example. The purpose of this example shall demonstrate how to use "Delegation". A full featured implementation of data tasks as shown in the example will require significant more effort. In this scenarios like these, "Delegation" will be the most preferred approach to accomplish this (IMHO).

Suppose we want to

  • Show a User
  • Modify (edit) a User
  • Create New a User, and
  • Delete a User

from within the detail view.

These "data tasks" shall not be performed by the detail view controller itself, instead a delegate is responsible for these data tasks.

These data actions shall be handled by the delegate:

@protocol UserDataSourceDelegateProtocol 
- (User*) viewControllerUser:(UserViewControllerBase*)viewController;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user;
@end

This protocol reflects the basic CRUD methods (Create, Read, Update, Delete).

Again, we don't want the Detail View Controller itself to perform these data methods, but instead this will be performed by an instance implementing the UserDataSourceDelegateProtocol. The detail view controller has a property of this delegate, and it sends these "data tasks" to the delegate.

There may be several detail view controllers, all subclasses of abstract class UserViewControllerBase which handle the show, edit and create tasks. Deletion of a user can be performed in the table view and in the "Show User" view controller:

  • ShowUserViewController
  • EditUserViewController
  • NewUserViewController

For example The EditUserViewController will send viewController:dismissWithUpdatedUser: when the user tabs the "back" button AND if the user has modified the user object. Now, the delegate may or may not allow to dismiss the detail view. It may disallow it when there are validation errors for example.

The UserDataSourceDelegateProtocol protocol may be implemented in the root view controller, the table view controller for example. However, a separate class whose sole responsibility is to handle data tasks may be more appropriate. In the sample below, the table view controller will also be this data handler.

The UserDataSourceDelegateProtocol may be defined in an extra header.

In UsersTableViewController.m:

#import "UserDataSourceDelegateProtocol.h"
#import "ShowUserViewController.h"


@interface UsersTableViewController ()
@property (nonatomic, readonly) NSArray* users;
@end


// This delegate will be called when the detail view controller request
// the user object which shall be displayed.
- (User*) viewControllerUser:(UserViewControllerBase*)viewController {
return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}

Here, the Table View Controller configures the Show User Detail View Controller:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserShowSegueID])
{
ShowUserViewController* showViewController = segue.destinationViewController;
showViewController.delegate = self; // Data Source Handler is self
}
}

The "Edit User" view controller is usually a destination view controller of the "Show User" view controller, which gets viewed when the user tabs the "Edit" button.

The "Show User" view controller will setup the delegate for the
"Edit User" view controller gets the same delegate:

In ShowUserViewController.m

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserEditSegueID])
{
EditUserViewController* editViewController = segue.destinationViewController;
editViewController.delegate = self.delegate; // pass through the data source hanlder
}
}

The data delegate may handle an updated user as follows:

In UsersTableViewController.m:

- (void) viewController:(UserViewControllerBase*)viewController
dismissWithUpdatedUser:(User*)user {
if (/* is valid user and can be saved */) {
[viewController.presentingViewController dismissViewControllerAnimated:YES
completion:nil];
}
}


Related Topics



Leave a reply



Submit