Swift tableView and prepareForSegue functions - ios

I am trying to get the tableView function to change the row before it goes into the prepareForSegue function. Below are the two functions:
This function is called when a cell is clicked and it changes the row variable to the current row that is clicked
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
row = indexPath.row
NSLog("You selected cell number: \(indexPath.row)!")
}
This function is for the segue from the cell that is clicked to the next window
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destViewController = segue.destinationViewController as! SecondView
destViewController.nameString = namesArray[getRow()]
}

I'm not sure what the getRow() method is, but it looks like you should just directly use your global row variable.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destViewController = segue.destinationViewController as! SecondView
destViewController.nameString = namesArray[row] // use your global variable row here
}

Related

Prepare for segue in TableViewDelegate methods

[SOLVED]
Let me explain my problem;
I have a bunch of Event object which appears in tableView cells.
And these objects store in events array
var events: [Event]
Also i have another view controller(DetailViewContoller), in that view controller i have a variable for receiving event object from tableview.
import UIKit
class EventDetailViewController: UIViewController {
var event: Event?
override func viewDidLoad() {
super.viewDidLoad()
print(event?.name)
}
When i tapped the cells i want to pass my current event object to variable(indicated on above) in DetailViewController. So i tried this ->
extension EventListViewcontroller:UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Whenever cells tapped, related object needs to pass DetailViewController
performSegue(withIdentifier: K.Segues.eventListToDetail, sender: self)
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == K.Segues.eventListToDetail {
let VC = segue.destination as! EventDetailViewController
VC.event = events[indexPath.row]
}
}
}
But unfortunately after segue performed when i checked the event variable in DetailViewController it was shown as a nil. So question is, how can i pass my tapped event cell to other view controller?
Note: i've found this topic How do you test UIStoryBoard segue is triggered by didSelectRow(at:) but it didn't help my problem...
In your class
class ViewController: EventListViewcontroller {
var selectedIndex: IndexPath? = nil
}
And change your code in didSelect as
extension ViewController:UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Whenever cells tapped, related object needs to pass DetailViewController
self.selectedIndex = indexPath
performSegue(withIdentifier: K.Segues.eventListToDetail, sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = self. selectedIndex, segue.identifier == K.Segues.eventListToDetail {
let VC = segue.destination as! EventDetailViewController
VC.event = events[indexPath.row]
}
}
}
Hope this helps

How can I tell to my prepare method on which cell a button has been pressed? [duplicate]

This question already has answers here:
How to get the indexpath.row when an element is activated?
(20 answers)
Closed 5 years ago.
I added a button #IBOutlet weak var cellButton: UIButton! in my custom tableViewCell class and an action of the button in my tableView controller
#IBAction func cellButtonTap(_ sender: UIButton) {
performSegue(withIdentifier: "goToMap" , sender: self)
}
what I need to do is to pass data to another viewController but is important to know on which cell the button has been pressed, so how can I tell my method prepare
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToMap"...//HERE I DON'T KNOW HOW TO DO
}
on which cell the button has been pressed? I'm a beginner and I've been looking for a solution for two days but I have not found it yet
You can do it with a "call back" closure...
class MyTableViewCell: UITableViewCell {
var didButtonTapAction : (()->())?
#IBAction func cellButtonTap(_ sender: UIButton) {
// call back closure
didButtonTapAction()?
}
}
in your table view controller, add a class-level variable:
var tappedIndexPath: IndexPath?
and then your table view cell setup becomes:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyTableViewCell
// set labels, colors, etc in your cell
// set a "call back" closure
cell.didButtonTapAction = {
() in
print("Button was tapped in cell at:", indexPath)
// you now have the indexPath of the cell containing the
// button that was tapped, so
// call performSegue() or do something else...
self.tappedIndexPath = indexPath
performSegue(withIdentifier: "goToMap" , sender: self)
}
return cell
}
and, in prepare:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToMap" {
// do what you need based on the row / section
// of the cell that had the button that was tapped, such as:
if let vc = segue.destination as? MyMapViewController {
vc.myData = self.dataArray[self.tappedIndexPath.row]
}
}
}
Are you sure you need a button at all? Normally it is happened through table view selection delegate.
If you need a button, you need to provide a way to identify what button was pressed. If you have simple one-dimensional array of items to present, simplest method is to setup button's tag to index
Like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "<id>", for: indexPath) as? Cell else { return UITableViewCell() }
cell.button.tag = indexPath.row
//...
return cell
}
then it will better to trigger segue with button as sender:
#IBAction func cellButtonTap(_ sender: UIButton) {
performSegue(withIdentifier: "goToMap" , sender: sender)
}
And you can get you data:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToMap", let index = (sender as? UIView)?.tag {
}
}

Swift/XCode - Why can't I pass data to the next view controller when a tableViewCell is pressed?

Apologies if this has already been answered elsewhere- I have spent the last two hours trying different things using similar suggestions but I still can't solve it!
Basically, I have a UITableView with custom cells(for different quiz topics) that when pressed, should allow the app to go to the next VC and pass an integer so the next VC knows which quiz to load. In my table view VC I have this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
rowPressed = indexPath.row
print ("rowPressed = \(rowPressed) before VC changes")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is GameVC {
let vc = segue.destination as? GameVC
vc?.toPass = rowPressed
print("I ran...")
} else {
print("You suck")
}
and in my GameVC I have this:
var toPass = Int()
override func viewDidLoad() {
super.viewDidLoad()
print("toPass = \(toPass)")
The console output when run is this:
I ran...
toPass = 0
rowPressed = 3 before VC changes
So it looks like the VC changes before the previous one can send the correct value of toPass. How do I fix this?
Many thanks in advance!
According to the segue description:
For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped.
So, sender is a UITableViewCell and you can do like below:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let cell = sender as? UITableViewCell else { return }
guard let idx = tableView.indexPath(for: cell) else { return }
guard let vc = segue.destination as? GameVC else { return }
vc.toPass = idx.row
}
The problem of your code was prepare(segue:) was invoked before tableView(didSelectRowAt:).
As suggested you have to call the performSegue method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// not necessary
//rowPressed = indexPath.row
//print ("rowPressed = \(rowPressed) before VC changes")
performSegueWithIdentifier("Your id", sender: indexPath)
//You can set the identifier in the storyboard, by clicking on the segue
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Your id"{
var vc = segue.destinationViewController as! GameVC
vc.toPass = (sender as! IndexPath).row
}
}
Because prepareForSegue is called before didSelectRowAt, you can also remove the segue from the Storyboard, drag and drop holding ctrl from the UITableViewController's yellow icon in the top to the second ViewController, click on the segue, give it an identifier, so now you can call performSegue:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.pressed = indexPath.row
self.performSegue(withIdentifier: "segue identifier", sender: nil)
}

Swift 2 - prepareForSegue nil Value

I am trying to send a link over another view when a select a row in UITableView.
When I select the row I can see the link is printed however, the value does not get to the function prepareForSegue.
It seems like the prepareForSegue function is called before the selection row in UITableView.
var videouserPath = ""
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
videouserPath = self.arrayUserVideo[indexPath.row][4]
print("tableview: ----\(videouserPath)")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
print("segue: ----\(videouserPath)")
if segue.identifier == "toUserVideo"
{
if let destinationVC = segue.destinationViewController as? GetVideo_ViewController{
destinationVC.videoToDisplay = videouserPath
}
}
}
I got in debug:
segue: ----
tableview: ----https://example.com/resources/1361929513_02-02-2016_125830.mov
Why is the segue function called before selection?
When linking UIStoryboardSegue to UITableViewCell from the storyboard, the messaging is in the order prepareForSegue, didSelectRowAtIndexPath.
Automatic Method
Bypass didSelectRowAtIndexPath altogether.
For general purpose and single selection cells, you do not need to implement didSelectRowAtIndexPath. Let the segue associated with UITAbleViewCell do the work, and handle selection like so:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailSegueIdentifier" {
if let indexPath = tableView.indexPathForSelectedRow {
print(indexPath)
}
}
}
Manual Method
If you absolutely need to do extra work before the segue, do not associate it to the UITableViewCell but to the UITableViewController. You will then need to trigger it programmatically. Inspiration here.
In IB, assign the segue to table view controller, give it an identifier (say detailSegueIdentifier), and invoke it like so.
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("didSelectRowAtIndexPath")
self.performSegueWithIdentifier("detailSegueIdentifier", sender: nil)
}
Passing parameters to the segue:
Invoking performSegueWithIdentifier will also give you a chance to explicitly pass parameters, not second-guess indexPathForSelectedRow, and not rely on a global(*).
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("didSelectRowAtIndexPath")
self.performSegueWithIdentifier("detailSegueIdentifier", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailSegueIdentifier" {
if let indexPath = sender as? NSIndexPath {
let name = db[indexPath.row].key
if let controller = segue.destinationViewController as? DetailViewController {
controller.name = name
}
}
}
}
(*) Don't ever rely on globals if you can help it.

Sending indexPath.row from didselectRowAtIndexPath to prepareForSegue via sender

I have seen many solutions however i cant get this right. I want to call prepareForSegue from the didSelectRowAtIndexPath function when a cell is tapped. Then i want to retrieve the row index that was tapped on, from inside the prepareForSegue function so i can use it to pass information to another view. I think i am calling the function correctly but there is something going wrong in my prepareForSegue function. I know its an easy solution i am just very stuck. Heres my current code
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("notificationsToAnswers", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//the below line is incorrect and should be something else
let selectedIndex = tableView.indexPathForSelectedRow?.row
//pass data on using the index
}
You should pass like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("notificationsToAnswers", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "notificationsToAnswers" {
//the below line is incorrect and should be something else
let selectedIndexPath = sender as! NSIndexPath
let index = selectedIndexPath.row
//pass data on using the index
}
}

Resources