Segue not getting selected row number - swift

I am passing data from a table view controller to a detail view. I tried using indexPath.row directly in my prepareForSegue method, however it displays an error of
use of unresolved identifier 'indexPath'
So, after searching the web, I set up the variable indexOfSelectedPerson which is assigned the value of indexPath.row. The problem when I run the app in the simulator is that prepareForSegue is getting the initial value of indexOfSelectedPerson (0), then getting the value of the selected row only after I click it. So, when I hit the back button in the Simulator and select a different row, the detail view shows the info of the row I selected the previous time.
import UIKit
class MasterTableViewController: UITableViewController {
var people = []
var indexOfSelectedPerson = 0
override func viewDidLoad() {
super.viewDidLoad()
people = ["Bob", "Doug", "Jill"]
}
override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
return 1
}
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return people.count
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView!.dequeueReusableCellWithIdentifier("personCell", forIndexPath: indexPath) as UITableViewCell
cell.text = "\(people[indexPath.row])"
return cell
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
indexOfSelectedPerson = indexPath.row
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if let mySegue = segue.identifier {
if mySegue == "personDetails" {
let detailsVC: DetailTableViewController = segue.destinationViewController as DetailTableViewController
detailsVC.selectedPersonName = "\(people[indexOfSelectedPerson])"
}
}
}
}
So, selecting Doug when the app first starts in the simulator displays the details for Bob because indexPathOfSelectedPerson is 0. Hitting the back button and then selecting Jill displays the details for Doug because indexPathOfSelectedPerson became 1 when I clicked on Doug the previous time. I'm guessing the problem stems from the order in which the methods are called.

The best way to do this kind of thing is not to use the delegate.
Updated Swift 4+
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedIndex = tableView.indexPath(for: sender as! UITableViewCell)
// Do your stuff with selectedIndex.row as the index
}
Original Answer
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
let selectedIndex = self.tableView.indexPathForCell(sender as UITableViewCell)
// Do your stuff with selectedIndex.row as the index
}

Swift 3 update:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedIndex = tableView.indexPath(for: sender as! UITableViewCell)!
// Do your actual preparing here...
}

//In didSelectRowAtIndexPath, you use this code:
func tableView(tvMain: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("yourSegueName", sender: nil)
}
//And prepareForSegue to get IndexPath and send your value
override func prepareForSegue(segue: UIStoryboardSegue,
sender: AnyObject!){
let indexPath : NSIndexPath = self.yourTableView.indexPathForSelectedRow()!
//make sure that the segue is going to secondViewController
let detailsVC = segue.destinationViewController as DetailTableViewController
detailsVC.selectedPersonName = "\(people[indexPath.row])"
}

Related

Passing Data to a tableViewController depending on button that was pressed

i'm a beginner in swift, but I do have a decent background in HTML,CSS, and some Java. I made this account to literally just ask this question, so i'll get straight to the point.
I really enjoy swift, but i've literally spent a f*cking week writing this same code over and over again, reviewing countless tutorials, books, guides, etc. To no avail; and i'm not going to lie, i'm getting reaaaaally tired of seeing 10+ errors stack up in my compiler as I keep trying to figure this out.
I have a ViewController, and I have a TableViewController - the ViewController being my home screen. On said viewController, I have two buttons, one is for BuildingItems, the other is BuildingBlocks. Both of which are segues.
on my TableViewController, I have buildBlocks and buildItems, both of which have their arrays defined.
What i'm trying to do, is depending on the button the user chose, I want that to then be the data that's used to populate my tableview. I can populate the tableview specifically by using the normal cell.textLabel?.text = arrayNameHere[indexPath.row] but obviously that doesn't solve my problem.
I hope that you're able to help me out here. I apologize for the crappy grammar and formatting, i've literally spent 4-5 hours a day this passed week trying to get this to work, and i've ended up just getting angry and deleting my entire project three different times. I'll include the code below. Again, excuse the formatting. I dont know why I can't seem to figure out swift, I keep trying every variation of delegate to try and pass something over that will let it work, but nothing is working.
ViewController:
#IBAction func BuildItems (_sender: Any) {
}
#IBAction func BuildBlocks (_sender: Any) {
}
In TableViewController:
let buildItems = ["these are all my", "arrays for this"]
let buildBlocks = ["same thing here","just saving time"]
class TableViewController: UITableViewController {
var myIndex = 0
override func tableView(_ tableView: UITableView, numberOfRowsInSection: Int) -> Int {
return buildItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell" for: indexPath)
cell.textLabel?.text = buildItems[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
}
}
You only need 1 segue: from the ViewController to the TableViewController.
In your ViewController make a variable for which button is pressed:
var category = ""
Change the value when a button is pressed, then segue:
#IBAction func BuildItems (_sender: Any) {
category = "BuildItems"
self.performSegue(withIdentifier: "segue", sender: self)
}
#IBAction func BuildBlocks (_sender: Any) {
category = "BuildBlocks"
self.performSegue(withIdentifier: "segue", sender: self)
}
Then in prepare:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
let vc = segue.destination as! TableViewController
// Assuming you created a variable called sentCategory in the TableViewController
vc.sentCategory = category
}
}
In your TableViewController create an empty array:
let data = [String]()
In viewDidLoad:
if sentCategory == "BuildItems" {
data = buildItems
} else {
data = buildBlocks
}
Populate your TableView with the data variable.
A couple comments:
Keep everything in your class scope, unless you have a good reason not to.
You don't need delegates in this scenario. Pass data with a prepare function as shown above.
Create bool var in your tableView controller maybe and helpArray
var dataArray:[String] = []
var isBuildItem:Bool = false
In your first controller implement prepareForSegue method like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TableViewController {
//set true or false it depends of which button you click
vc.isBuildItem = //true or false
}
}
Then in viewDidLoad in your TableViewController check bool variable
if(isBuildItem:Bool){
dataArray = buildItems
}
else{
dataArray = buildBlocks
}
In all your tableView delegate methods change buildItems array with dataArray
in your ViewController:
import UIKit
var segueName = ""
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
segueName = segue.identifier!
print(segueName)
}
}
TableViewController:
import UIKit
class TableViewController: UITableViewController
{
let animals = ["Cat","Dog","Mouse"]
let colors = ["White","Blue","Red"]
var arrayResult = [""]
override func viewDidLoad()
{
super.viewDidLoad()
if segueName == "seguebuttonA"
{
arrayResult = animals
}
else if segueName == "seguebuttonB"
{
arrayResult = colors
}
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
{
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// #warning Incomplete implementation, return the number of rows
return arrayResult.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTest", for: indexPath) as! TableViewCell
// Configure the cell...
cell.titleLabel.text = arrayResult[indexPath.row]
return cell
}
}
Add segue name:
The complete example is in the link below, I hope I have helped, if you have any questions let me know.
https://github.com/cwilliams26/viewSegueTabelview/tree/master

Prepareforsegue not passing the appropriate value to destination Viewcontroller?

I have two viewcontrollers (one is tableVC) that I would like to pass information between. Here is code from that tableVC:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var rowSelected = indexPath.row
print(rowSelected) //always returns the correct integer
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController: newController = segue.destination as! newController
newController.rowSelected = rowSelected
}
performSegue(withIdentifier: "rowSelected", sender: Any?.self)//segue to newController
}
And here is the code for the newController that I want the info to be passed to:
#IBOutlet weak var label: UILabel!
var rowSelected = Int()
override func viewDidLoad() {
super.viewDidLoad()
label.text = infoArray[rowSelected]
print(rowSelected) //always logs 0 to the console, regardless of cell selection
}
I thought I had set this up appropriately, but for whatever reason the index called to the infoArray is always 0, no matter what cell is selected in the tableVC. Not sure what the problem is.
write prepareForSegue in class scope/global scope. in your code prepareForSegue will never call because you are writing this inside the method. pass rowSelected in performSegue and get rowSelected value in prepareForSegue using sender or you can use indexPathForSelectedRow property of tableView.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
performSegue(withIdentifier: "rowSelected", sender: rowSelected)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: Any?) {
let rowSelected = sender as! Int
// or you can use indexPathForSelectedRow for getting row value
// let indexPath = self.tableView.indexPathForSelectedRow?
// let rowSelected = indexPath!.row
let destViewController: newController = segue.destination as! newController
newController.rowSelected = rowSelected
}
Need to use override in your function when you prepareForSegue
See below example code : -
Swift 3
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowAttractionDetails" {
let detailViewController = segue.destination
as! AttractionDetailViewController
let myIndexPath = self.tableView.indexPathForSelectedRow!
let row = myIndexPath.row
detailViewController.webSite = webAddresses[row]
}
}
Swift 2.3
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowAttractionDetails" {
let detailViewController = segue.destination
as! AttractionDetailViewController
let myIndexPath = self.tableView.indexPathForSelectedRow!
let row = myIndexPath.row
detailViewController.webSite = webAddresses[row]
}
}
Source - Segue from UITableViewCell Taps in Swift & TableView Navigation using Storyboards in Xcode 8

Second segue from TableViewController creating SIGABRT error relating to the first

I have created a NoteBook application within a larger app. I have all the functionality working including a segue to an Add Note page which triggers programatically from clicking a note (to edit it) or a + barButtonItem.
I need a second segue to send the user back to the home page of the app, but every way I seem to try it conflicts with the existing segue I have in place.
Can anyone suggest a way to get the second segue to work. They both have different identifiers which I am referencing in the methods. Its just the goHome segue that will not work...
class NoteBookViewController: UITableViewController, NoteViewDelegate {
func didUpdateNoteWithTitle(newTitle: String, andBody newBody: String) {
self.noteBookEntries[self.selectedIndex] ["title"] = newTitle
self.noteBookEntries[self.selectedIndex] ["body"] = newBody
self.tableView.reloadData()
saveNotesArray()
}
var noteBookEntries = [[String:String]] ()
#IBAction func newNote() {
var newNote = ["title" : "", "body" : ""]
noteBookEntries.insert(newNote, at: 0)
self.selectedIndex = 0
self.tableView.reloadData()
saveNotesArray()
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
var selectedIndex = -1
func saveNotesArray() {
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
UserDefaults.standard.synchronize()
}
override func viewDidLoad() {
super.viewDidLoad()
if let newNote = UserDefaults.standard.array(forKey: "notes") as? [[String:String]] {
noteBookEntries = newNote
}
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.reply, target: self, action: #selector(NoteBookViewController.navigateToNextViewController))
}
func navigateToNextViewController(){
self.performSegue(withIdentifier: "goHome", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return noteBookEntries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell (withIdentifier: "CELL")! as UITableViewCell
cell.textLabel?.text = noteBookEntries[indexPath.row]["title"]
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
noteBookEntries.remove(at: indexPath.row)
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath.row
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
notesEditorVC.navigationItem.title = noteBookEntries[self.selectedIndex] ["title"]
notesEditorVC.noteBodyText = noteBookEntries[self.selectedIndex] ["body"]
notesEditorVC.delegate = self
}
}
error message relating to original segue - this segue works until the second is added
In your prepareForSegue method first line is:
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
This method is called for each of your segues. When it is called for your first segue it works totally fine because the destination view controller is, in fact, of type NewNoteBookEntryViewController.
However, when this method is called for your second segue, the destination controller is of different type. So, you get a crash when you force downcast it.
You should add some logic to your prepareForSegue method so that you distinguish between segues. For example:
if segue.identifier == "addNote" {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
//some other code
}
Solved by adding the logic and then adding this to the destination controller:
override func viewWillAppear(animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}

fatal error: unexpectedly found nil while unwrapping an Optional value: Swift, Core Data

I am getting error on the line:
let indexPath = self.menuTable.indexPathForSelectedRow()!.
Seems that I am not getting a value from indexPathForSelectedRow. I am parsing from a CSV file into Core Data. Not sure if it matters. I am new to coding, so not sure if I am missing something obvious.
import UIKit
import CoreData
class MenuTableViewController: UITableViewController {
#IBOutlet var menuTable: UITableView!
private var menuItems:[MenuItem] = []
var fetchResultController:NSFetchedResultsController!
override func viewDidLoad() {
super.viewDidLoad()
// Load menu items from database
if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
let fetchRequest = NSFetchRequest(entityName: "MenuItem")
var e: NSError?
menuItems = managedObjectContext.executeFetchRequest(fetchRequest, error: &e) as! [MenuItem]
if e != nil {
println("Failed to retrieve record: \(e!.localizedDescription)")
}
}
// Make the cell self size
self.tableView.estimatedRowHeight = 66.0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.layoutIfNeeded()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return menuItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = menuTable.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuTableViewCell
// Configure the cell...
cell.nameLabel.text = menuItems[indexPath.row].name
cell.detailLabel.text = menuItems[indexPath.row].detail
// cell.priceLabel.text = "$\(menuItems[indexPath.row].price as! Double)"
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("showFront", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "showFront")
{
var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController
let indexPath = self.menuTable.indexPathForSelectedRow()!
let titleString = menuItems[indexPath.row].name
upcoming.titleStringViaSegue = titleString
self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)
}
}
}
Since you have an implementation of tableView:didSelectRowAtIndexPath: and the cell is connected to the segue in the storyboard, the segue is happening twice. The second time the segue is performed there would be no selection because you deselect it during the first segue. You can fix this issue by deleting your implementation of tableView:didSelectRowAtIndexPath: or by creating the segue in the storyboard with the view controller itself as the source instead of the cell and leaving your manual invocation of the segue.
I don't know if this is the problem but why are u using self as sender if u need the indexPath?
Try:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("showFront", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "showFront")
{
var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController
let titleString = menuItems[indexPath.row].name
upcoming.titleStringViaSegue = titleString
self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)
}
}
I see you are using a UITableViewController. In a UITableViewController a UITableView is automatically created for you with the needed outlets. You can access it in code via self.tableView. My guess is that you do not connected the IBOutlet for your UITableView called menuTable. So the optional which is nil while unwrapping is not the indexPath but the UITableView.
Fix:
Delete your IBOutlet and everywhere you use the menuTable variable and use self.tableView instead.

Send data from TableView to DetailView Swift

I'm trying to do maybe one of the simplest and more confusing things for me until now
I wanna develop my own App , and in order to do it I need to be able to passing some information depending of which row user click (it's Swift lenguage)
We have a RootViewController(table view) and a DetailViewController (with 1 label and 1 image)
(our view)
Here is the code:
#IBOutlet weak var tableView: UITableView!
var vehicleData : [String] = ["Ferrari 458" , "Lamborghini Murcielago" , "Bugatti Veyron", "Mercedes Benz Biome"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var nib = UINib(nibName: "TableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vehicleData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:TableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as TableViewCell
cell.lblCarName.text = vehicleData[indexPath.row]
cell.imgCar.image = UIImage(named: vehicleData[indexPath.row])
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("DetailView", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "DetailView") {
var vc = segue.destinationViewController as DetailViewController
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
Custom TableViewCell class (has a xib File with cell)
class TableViewCell: UITableViewCell {
#IBOutlet weak var lblCarName: UILabel!
#IBOutlet weak var imgCar: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class DetailViewController: UIViewController {
#IBOutlet weak var lblDetail: UILabel!
#IBOutlet weak var imgDetail: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
The question is:
if user click Ferrari 458 , the lblDetail in DetailViewController would show: Ferrari 458 is a super car which is able to reach 325 km/ h ...... (whatever we want)
and imgDetail would be able to show an image (whatever we want) of the car
If user click Bugatti Veyron now the lblDetail show us: Bugatti Veyron is a perfect and super sport machine. It's one of the fastest car in the world....
imgDetail show us an image of this car
Same thing with all cars depending which row we have clicked
I know the work is around prepareForSegue func in first View Controller but i was trying a lot of different ways to make it possible and anything runs ok
How we can do this???
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
}
}
This may be another solution, without much code in didSelectRowAtIndexPath method.
Note that while it may look cleaner, and we do not need an extra variable valueToPass, it may not be a best practice, because the sender argument inside performSegue method is supposed to be the actual object that initiated the segue (or nil).
// MARK: UITableViewDelegate methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "goToSecondVC", sender: indexPath)
}
// MARK: UIViewController methods
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecondVC" {
if segue.destination.isKind(of: CarDetailsController.self) {
let secondVC = segue.destination as! CarDetailsController
let indexPath = sender as! IndexPath
secondVC.passedValue = carsArray[indexPath.row]
}
}
}
If you drag a segue from the prototype cell (in the Interface Builder) to your next View Controller and set its segue identifier to "Your Segue Identifier", you can also do it with this shortcut:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Your Segue Identifier" {
let cell = sender as! YourCustomCell
let vc = segue.destination as! PushedViewController
vc.valueToPass = cell.textLabel?.text // or custom label
}
}
And you also don't need the performSegueWithIdentifier() in the didSelectRowAtIndexPath(), nor this Table View method.
In PushedViewController.swift (the next View Controller):
var valueToPass: String!
override func viewDidLoad() {
super.viewDidLoad()
yourLabel.text = valueToPass
}
It's important to set the label's value after it initialized from the Storyboard. That means, you can't set the label in the previous View Controller's prepareForSegue() directly, therefore needing to pass it with valueToPass.
Its simple, am adding one statement to above answer.
To get the selected car name in detail view label,
lblDetail.text = passedValue
you can add this code of line in viewDidLoad() func of your detailed view. passedValue contains the name of car which user selected(assign in prepareForSegue) then you can assign to your detailedView label.
Hope it helps!!