Prepareforsegue not passing the appropriate value to destination Viewcontroller? - swift

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

Related

assign the selected indexpath.row to a variable in another class

I show the data in labelTEx in the table.
When I click labelTEx, I open another table class.
I want to transfer the text data of labelTExt that I clicked in UITableViewCell to formBaslik in DetayViewController.
that is, I want to transfer the gifsabaslik [indexPath.row] that I have selected to the detayBaslik in DetayViewController. How can I do that?
DetayViewController
class DetayViewController: UIViewController {
var formBaslik = String()
}
TableViewController
class TableViewController: UIViewController{
var gifsayeniresim: [String] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! TableViewCell
cell.labelTExt.text = self.gifsabaslik[indexPath.row]
cell.labelTExt.textColor = UIColor.white
cell.labelTExt.font = UIFont(name: "HelveticaNeue", size: 14.0)!
cell.labelTExt.backgroundColor = UIColor.lightGray
cell.labelLayout.constant = cell.labelTExt.contentSize.height
cell.labelTExt.isEditable = false
let tap = UITapGestureRecognizer(target: self,action: #selector(handleTaponTextField(_:)))
tap.numberOfTapsRequired = 1
tap.delegate = self
cell.labelTExt.isUserInteractionEnabled = true
cell.labelTExt.addGestureRecognizer(tap)
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "newo"{
if segue.destination is DetayViewController {
}
}
#SH Yasilm
In DetayViewController, declare
var formBaslik = String?
In TableViewController, in prepare, write
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "newo" {
if let cell = sender as? UITableViewCell {
// You have clicked in a cell, but that may not have selected it: let's compute its indePath
let tapPosition:CGPoint = cell.convert(CGPoint.zero, to: self.table)
let indexPath = self.table.indexPathForRow(at: tapPosition)
if let vc = segue.destination as? DetayViewController {
vc.formBaslik = gifsabaslik[indexPath.row]
}
}
}
You can retrieve the indexPath by following the code below.
In the DetayViewController's very top (below class)
var myStr: String!
Inside the class where you have the tableview
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "newo"{
if segue.destination is DetayViewController {
let vc = segue.destination as? DetayViewController
let indexPath = self.tableView.indexPathForSelectedRow
let cell = tableView.cellForRow(at: indexPath!) as! YourCellClassName
vc.myStr = cell.yourString
//NOTE! If. the cell is a string just do like I did, other way, if that's a textfield/label you should use cell.yourLabel.text
}
}

How to append string to tableview from separate ViewController using alert

I'm trying to append string using an alert in createPlaylistVC to a tableView in another ViewController createdPlaylistVC.
I've looked up this answer and it didn't do much for me
add a row to the tableView from another viewController
CreatePlaylistVC
var crdPlaylistVC = CreatedPlaylistVC()
alert.addAction(UIAlertAction(title:"OK", style:.default, handler: {
action in
if let playlistName = alert.textFields?.first?.text {
self.crdPlaylistVC.emptyArray.append("Your playlist: \(playlistName)")
let indexPath = IndexPath(row: self.crdPlaylistVC.emptyArray.count - 1, section: 0)
self.crdPlaylistVC.tableView?.beginUpdates()
self.crdPlaylistVC.tableView?.insertRows(at: [indexPath], with: .automatic)
self.crdPlaylistVC.tableView?.endUpdates()
self.crdPlaylistVC.tableView?.reloadData()
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let SEC: CreatedPlaylistVC = segue.destination as! CreatedPlaylistVC
SEC.emptyArray.append("Your playlist: \(playlistName)")
self.crdPlaylistVC.tableView.reloadData()
}
CreatedPlaylistVC
class CreatedPlaylistVC:UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var emptyArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "playlistCell", for: indexPath) as! UITableViewCell
cell.textLabel?.text = emptyArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return emptyArray.count
}
}
The code cannot work. createdPlaylistVC() is never the instance in the storyboard.
You have to call performSegue in the action and pass the string as sender. And prepare for must be on the top level of the class
var crdPlaylistVC = createdPlaylistVC()
alert.addAction(UIAlertAction(title:"OK", style:.default) { [weak self] action in
if let playlistName = alert.textFields?.first?.text {
self?.performSegue(withIdentifier: "MyIdentifier" sender: playlistName)
}
}
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "MyIdentifier" else { return }
let playlistName = sender as! String
let sec = segue.destination as! createdPlaylistVC
sec.emptyArray.append("Your playlist: \(playlistName)")
}
You have to reload the table view in createdPlaylistVC because the table view might be not connected yet.
And please conform to the naming convention that class names start with an uppercase letter and variable names start with a lowercase letter.

Error within tableView when swapping detailView for a different view

I have the function
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let indexPath = tableView.indexPathForSelectedRow {
let object = dailyAgenda[indexPath.row]
if object == "Time Management" {
self.performSegue(withIdentifier: "showTimeManagement", sender: self)
}
else {
self.performSegue(withIdentifier: "showDetail", sender: self)
}}}
And the prepare for segue function
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = dailyAgenda[indexPath.row]
var controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.textDescription = indepthDescript[indexPath.row]
}}
if segue.identifier == "showTimeManagement" {
var controller = (segue.destination as! UINavigationController).topViewController as! TimeManagement
}
}
But I keep getting the error "Thread 1: Fatal error: Index out of range" when selecting the cell that performs the showTimeManagement segue. The error occurs on the "controller.textDescription = indepthDescript[indexPath.row]]" line within the showDetail segue. Why would it even be running this line in the first place and where am I going wrong?

custom cell segue using button swift

I have created custom cell with button inside. Now I am trying to pass a data via pressing on this button, but cant catch indexPath, need your help.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier=="editData"){
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = (segue.destinationViewController as! AddDetail)
destinationController.info = data[indexPath.row]
let nItem : Dealers = data [indexPath.row]
destinationController.nItem = nItem
also Im trying do the same but from swiping menu:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?{
let edit = UITableViewRowAction(style: .Normal, title: "Edit") { (action, indexPath) in
self.performSegueWithIdentifier("addDealer", sender: self)
let name = self.data [indexPath.row].dealerName
print(name)
}
edit.backgroundColor = UIColor.lightGrayColor()
return [delete, edit]
is it possible pass segue from swiping menu?
You can pass indexPath as the sender in performSegueWithIdentifier.
self.performSegueWithIdentifier("addDealer", sender: indexPath)
then
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = sender as? NSIndexPath {
// then here you know what the indexPath was
// and can do whatever you want with it
}
...
Try using tableView.indexPathForCell(selectedCell) instead of tableView.indexPathForSelectedRow; you first extract selectedCell as your custom table view cell (YourCustomTableViewCell below):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
if segue.identifier == "editData" {
let destinationController = segue.destinationViewController as! AddDetail
if let selectedCell = sender as? YourCustomTableViewCell {
let indexPath = tableView.indexPathForCell(selectedCell)!
destinationController.info = data[indexPath.row]
let nItem : Dealers = data[indexPath.row]
destinationController.nItem = nItem
}
}
}
As for the swiping question: I'll get back answer to this.

Segue not getting selected row number

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