Passing Data Between View Controllers in Swift (From Tableview to Detailviewcontroller)

Passing data between View Controllers in Swift (From TableView to DetailViewController)

First and foremost, I'm assuming your MyTableViewController class conforms to both UITableViewDataSource and UITableViewDelegate protocols and that you've set your MyTableViewController class to be the delegate in code or via Storyboard.

With that sorted out,there are multiple ways to achieve the result you seek.
You can declare your ImageArray in an independent class and call it inside your MyTableViewController class, index them onto a tableView using the tableView delegate methods, and finally using the prepareForSegue method to push your images onto your myViewController. Or you can simply declare and initialize your ImageArray at the top of your MyTableViewController class like below:

var ImageArray = [("Moscow Russia.jpg", "Europe"),
("London England.jpg", "Europe")]

In the ImageArray above, ensure that your image name matches exactly as the asset name you've imported into your Xcode project.

Then we specify how many rows in section we need ImageArray to occupy on our tableView (i.e. basically count our ImageArray into our TableView) with below required method:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return ImageArray.count ?? 0
}

Next, you want to present your ImageArray in each row of of the cell using the tableView:cellForRowAtIndexPath: method.

Side Note on your TableCell: Hopefully your TableCell is subclassed from UITableViewCell and you have already declared and connected two IBOutlets, say, imageView and textLabel respectively. Also, ensure your TableCell is properly linked to your prototype cell in Storyboard under Identity Inspector) Your TableCell class should look something like below:

import UIKit
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textLabel: UILabel!
}

Now back into your MyTableVIewController class. From your code, I see you're casting the line 'let cell = ...' as 'UITableViewCell. You should rather cast it as 'TableCell' instead since you're subclassing it. Implement the tableView:cellForRowAtIndexPath: method as follows:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! TableCell

//Note that I'm using tuples here. Pretty cool huh. Got to love Swift!
let (imageName, textNameToGoWithImage) = ImageArray[indexPath.row]

cell.textLabel.text = textNameToGoWithImage
cell.imageView.image = UIImage(named: imageName)
cell.imageView.contentMode = .ScaleAspectFit

// You could have also used 'if let' in optional binding to safely unwrap your image if you want like below.
// if let image = UIImage(named: imageName){
// cell.imageView?.image = image
// cell.imageView.contentMode = .ScaleAspectFit
// }

return cell
}

It looks like you're a little confused about when and where to use performSegueWithIdentifier method as opposed to using -prepareForSegue method. And even when to use the tableView:didSelectRowAtIndexPath method.

Let me briefly explain here. You use the performSegueWithIdentifier method when you didn't control-drag a segue from one ViewController's scene to another in Storyboard. This way, using the performSegueWithIdentifier method will allow you to move between ViewController scenes as long as you specify the right identifier which you've set in Storyboard under 'Attributes Inspector.'

Now if you're using Storyboard instead, you wouldn't need the tableView:didSelectRowAtIndexPath method. What the tableView:didSelectRowAtIndexPath method does is that it tells the delegate that the specified row is now selected and we can do something within its code body (like push an image or a text onto another ViewController Scene like you're trying to do). But that becomes redundant when you use segues. All you have to do, is to control-drag a segue from the table cell on your MyTableViewController scene to your myViewController scene. Choose 'Show' and give the segue an identifier name like you've done "next". (A little side note: if you want the Back button functionality to display at top navigator bar when you run your app, you simply embed your MyTableViewController in a UINavigationController to give you that 'Back' button functionality. With your MyTableViewController Scene selected in Storyboard, Go to the top menu and select Editor >> Embed In >> Navigation Controller. Then walla!!)

Lets now go ahead and implement our tableView:prepareForSegue method like below:

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "next" {
//Note that, originally, destinationViewController is of Type UIViewController and has to be casted as myViewController instead since that's the ViewController we trying to go to.
let destinationVC = segue.destinationViewController as! myViewController

if let indexPath = self.tableView.indexPathForSelectedRow{

let selectedRow = ImageArray[indexPath.row]

destinationVC.imageName2 = selectedRow.0
destinationVC.textName2 = selectedRow.1
}

From the above code, make sure you set the 'imageName' and 'textName' as properties in your myViewController class first before you can access them with 'destinationVC' which is now of type myViewController. These two properties will hold the data we are passing from MyTableViewController class to myViewController class. And we are using the array index to pass data to these two properties accordingly.

You can then create two IBOutlets to display your image and text by passing these set 'imageName2' and 'textName2' properties to your outlets (or any UI control for that matter).

  • Now the reason why you will have to set properties first in
    myViewController class before you pass them on or around (i.e. to a
    UI element, closure, another VC etc) is that, when you hit a tableView cell from
    MyTableViewController scene to segue onto your next ViewController
    scene (i.e. your myViewController scene), iOS hasn't instantiated
    that second scene just yet. And so you need a property to hold onto the data
    you're trying to pass onto your second scene View Controller first so that you can
    make use of it later when that class finally loads.

So your myViewController class should look something like below:

import UIKit

class myViewController : UIViewController {

//Your two strings to initially hold onto the data
//being passed to myViewController class
var imageName2 : String?
var textName2 : String?

@IBOutlet weak var detailImageView: UIImageView!
@IBOutlet weak var detailTextNameLabel: UITextField!

override func viewDidLoad() {
super.viewDidLoad()

detailTextNameLabel.text = textName2!

if let image = UIImage(named: imageName2!) {
self.detailImageView.image = image
}
}

And that's it!

Things to note on labelling and conventions in Swift:

  • Start naming classes with block letters (i.e. class
    ViewController() {})
  • Classes and properties should capture the meaning of what they
    represent. I will recommend you change your MyTableViewController
    and 'myViewController'classes accordingly to reflect what they truly
    mean or do (You can go with 'MainTableViewController' and 'DetailViewController'. That will do just fine).
  • Use camelToe labelling for properties and methods. (I used the labels you
    provided in your question in order not to confuse you too much).

    Enjoy!

Passing data from tableView to ViewController in Swift

Try this.

ModelViewViewController

var selectedImage:String?
var selectedLabel:String?

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("Row \(indexPath.row)selected")
selectedImage = self.tableData[indexPath.row]
selectedLabel = self.tableData[indexPath.row]
performSegueWithIdentifier("detailView", sender: self)
}

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

if(segue.identifier == "detailView") {
var vc = segue.destinationViewController as DetailViewController
vc.img = selectedImage
vc.lblDetail = selectedLabel
}
}

class DetailViewController: UIViewController {
@IBOutlet var imgDetail: UIImage!
@IBOutlet var lblDetail: UILabel!
var img:String?

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

imgDetail = UIImage(named: img)
}

This should work.

Swift 4: Passing Data from Tableview to ViewController

Your problem seems simple:

var image = [UIImage]()   // lost here

That's an ARRAY of images.

Suggest for a single item, you want a single image?

var image:UIImage!

Warning, will crash if image is nil when used. (alternate use UIImage? but must unwrap).

Therereby, in the table view controller..

vc.image = foodImage[indexPath.section][indexPath.row]

Will be behave as expected. No need to use:

self.itemImage.image = UIImage(named: image) //not working!!! Cant seem to find the right code for this from converting UIIMAGE to String. I am just lost!

(Which is incorrect because you're trying to use an array of images to pass to the STRING parameter of load image from file.)

Just use:

self.itemImage.image = self.image

As they are both image types.

You do the correct thing in the cell and index the array within the array to get the image, so do the same here and have a singe image type in your detail view controller. In that way if you click beef, the image for beef is sent.

As an aside, consider using a data model type for your recipe.

class Ingredient {
var name:String = ""
var image:UIImage! = nil
var count:Int = 0
var calories:Int = 0

public init(name: String, image: UIImage, count: Int, calories: Int) {
self.name = name
self.image = image
self.count = count
self.calories = calories
}
}

then you can do say:

let ingredients = [Ingredient("Beef", beefImage, 100, 350), Ingredient("Onion", onionImage, 1, 20)]

or etc,

Send data from TableView to DetailView Swift

Here is the example for you:

var valueToPass:String!

func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")

// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell

valueToPass = currentCell.textLabel.text
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}

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

if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}

But don't forget to create a passedValue variable into your DetailViewController.

This is just an example of passing data from one viewController to another and you can pass data with this example as you need.

And for more info refer this links.

Passing values between ViewControllers based on list selection in Swift

Use didSelectRowAtIndexPath or prepareForSegue method for UITableView?

Swift: Pass UITableViewCell label to new ViewController

https://teamtreehouse.com/forum/help-swift-segue-with-variables-is-not-working

May be this will help you.

Swift 3.0

var valueToPass:String!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")

// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell

valueToPass = currentCell.textLabel?.text
performSegue(withIdentifier: "yourSegueIdentifer", sender: self)
}

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

if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destination as! AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}

Pass data between viewcontroller with out segues

Your code has a problem in your didSelectRowAt, since you are not passing the previously created DetailViewController with a restaurant, but another newly-created DetailViewController, try this:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let detailView: DetailViewController = DetailViewController()
detailView.restaurant = restaurants[indexPath.row]
self.navigationController?.pushViewController(detailView, animated: false)
}

See the change on the pushViewController method? This should do it.

Pass Data (Label) from TableViewCell to another ViewController

Quick solution:

  1. Change
    performSegue(withIdentifier: "yourSegueIdentifer", sender: self) to performSegue(withIdentifier: "yourSegueIdentifer", sender: valueToPass)

2.Your prepare for Segue method should looks like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueIdentifer" {
let destinationViewController = segue.destination as! AnotherViewController
destinationViewController.valueToPass = sender as? String
}
}

  1. On AnotherViewController create var valuteToPass: String = "" and set your label.text = valueToPass

But I think you should not use currentCell.textLabel.text value, instead use the original value. (like if you set your currentCell as cell.textLabel.cell = array[indexPath.row], your valueToPass should be valueToPass = array[indexPath.row])

EDIT:

You use didDeselectRowAt method, instead of didSelectRowAt.

Change func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

Don't use global variable, create it in didSelectRowAt.

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")

// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell

let valueToPass = currentCell.textLabel?.text
print("value: \(valuteToPass)")

performSegue(withIdentifier: "toDetails", sender: valueToPass)
}

On DestinationController:

class DestinationController: UIViewController {

var valuteToPass: String = ""

override func viewDidLoad() {
super.viewDidLoad()
jobLabel.text = valueToPass
}

}

EDIT2

JobTableViewController

  1. delete var valueToPass:String!

Change let valueToPass = jobs[indexPath.row].text instead of let valueToPass = currentCell.textLabel?.text
I checked this change in your code, this will work.



Related Topics



Leave a reply



Submit