Pass Data Through Segue

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 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 via segue using didSelectRowAt

Your prepare for segue should not be in inside override func tableView( move it so its like this:

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

rowselected = indexPath.row
self.performSegue(withIdentifier: "dayx", sender: self)

}

also should be override:

   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "dayx" {
let destinationVC = segue.destination as! foodinfo
destinationVC.counter = rowselected
}
}

because override func prepareForSegue method is called after self.performSegue. So now you can successfully set the value rowSelected = indexPath.row inside override func tableView( and when self.performSegue is called it will correctly pass the data as set in the override func prepareForSegue

How can I pass data between views via segue in a Xamarin.mac Cocoa app?

First, you need to set a public property in your second view controller :

public Person MainPerson { get; set; }

You’ll need to override the method called PrepareForSegue. Inside it, you identify the destination controller (your second view), and in case you have multiple segues, it is a good practice to use a switch case statement.


public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);

switch (segue.Identifier)
{
case "LaunchSecondView":
{
SecondViewClass target = segue.DestinationController as SecondViewClass;
target.Person = CurrentPerson;
}
break;
}
}

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?

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

Pass data with segue Model View Presenter

You asked:

Is correct to calling vc presenter (like in first class when I call homeDetailVC.presenter.convertData(homeData: home[selectedIndex])) during segue?

I would generally avoid having a view controller reach in and call some method of some property (i.e., the presenter) of another view controller. You are tightly coupling/entangling each source view controller with implementation details of its destination view controller(s). E.g., you are requiring that the home view controller knows that the details view controller has a presenter, and that this presenter has a convertData method, etc.

That is not good. You want to keep all of these various classes as loosely coupled as possible. All you care about is whether the destination view controller can receive some data.

Here is one example implementation. E.g., I might suggest a protocol to indicate whether the destination can receive some particular model object(s), e.g.,

protocol WorkoutDetailsReceiver {                   // is some destination capable of receiving `Workout` information
func receive(_ value: Workout)
}

Then the presenter for the destination view controller would conform to this, updating its model with the supplied value:

extension HomeDetailsPresenter: WorkoutDetailsReceiver {
func receive(_ value: Workout) {
workout = value // e.g. save the data that was passed to this presenter

// And if you want to do some conversion/processing of the data, do that here,
// but the caller should not be involved in those sorts of details.
}
}

But rather than having the source view controller from reaching into the destination view controller and invoke some method in its presenter, I personally use the same protocol, with a simple implementation that passes it along to its presenter:

extension HomeDetailsVC: WorkoutDetailsReceiver {
func receive(_ value: Workout) {
presenter.receive(value)
}
}

Having set up this pattern for receiving data, now the home view controller only needs to see if the destination can receive the Workout information:

class HomeViewController: UIViewController {
lazy var presenter = HomePresenter(delegate: self)

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let receiver = segue.destination as? WorkoutDetailsReceiver {
presenter.supplyWorkout(to: receiver)
}
}
}

Note, because we have a MVP app, the HomeViewController does not hold any model data. Its own presenter has that. So we have some method for the source view controller to pass along the necessary data to the destination.

E.g.,

class HomePresenter {
private weak var delegate: HomePresenterDelegate?
private var workouts: [Workout] = []
private var selectedIndex: Int?

init(delegate: HomePresenterDelegate) {
self.delegate = delegate
}

// just as an example

func supplyWorkout(to receiver: WorkoutDetailsReceiver) {
guard let selectedIndex = selectedIndex else {
return
}

receiver.receive(workouts[selectedIndex])
}

...
}

Anyway, the end result is that the home view controller only needs to know whether the destination (the details view controller) can receive the information that you want to pass.


  1. Using MVP pattern is correct to take values directly from presenter when prepare segue (like in homeDetailsVC in preparing segue destinationVC.workoutNameText = presenter.titleValue)? Or maybe better approach is create variables directly in view controller and update them from presenter with delegates?

I once tried this “individual properties” approach: It works, but I found it to be brittle. As the app evolves, you want to change what data the destination wants, and if you have individual variables, it is too easy to forget about some property that needs to be passed along. Also, as you start injecting lots of properties from one scene to another, you end up littering the view controller with a lot of those staging properties (whether stored or computed) that really belong in its presenter. By having a protocol, you have a simple, consistent contract between the source and destination about what data the destination expects.

Now, all of that having been said, do not get too lost in the above details. There are lots of variations on the theme. But the governing principle is that we should keep our objects loosely coupled.



Related Topics



Leave a reply



Submit