Passing Object from Table View Cell to Another View Controller Via Segue - swift

I have the following portion of my code that I'm trying to work out in order to move from a table view controller to a view controller.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let donation = donations[indexPath.row]
print(donation)
self.performSegue(withIdentifier: "showDonationReviewForm", sender: Any?)
}
On the above, when I print donation, it correctly prints the object and it's related fields. I know at some point I would need to use override func prepare(for segue... but I don't know how I am passing along the donation object to the next controller.

You can try
performSegue(withIdentifier: "showDonationReviewForm", sender:donations[indexPath.row])
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDonationReviewForm" {
if let nextViewController = segue.destination as? NextViewController {
nextViewController.toSend = sender as! Donation
}
}
}
class NextViewController :UIViewController {
var toSend:Donation?
....
}
Assuming donations is an array of Donation model

Related

How do I use indexpathforselectedrow to get an instance from my array of structs?

I'm building an app for school. The app is sort of a dictionary app that includes a table of vocabulary words (my WordsTableViewController) embedded into a navigation controller, and my Definition View Controller which shows the vocab word and its corresponding definition.
The problem is that I have no idea how to use indexpathforselectedrow to get the appropriate vocabulary word from my vocabController's vocabWords array. The 'Vocabulary Words' are struct instances located in its own separate swift file.
All of it will be in my prepare for segue inside of my WordsTableViewController swift file.
Any help is really appreciated.
The table views number of rows looks like this:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myListVocab.vocabWords.count
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowDefinitionSegue" {
if let definitionVC = segue.destination as? DefinitionViewController {
let index = tableView.indexPathForSelectedRow
let indexPathForSelectedRow = index.row
definitionVC.vocabWord[index]
let vocab = myListVocab.vocabWords[indexPathForSelectedRow]
}
}
}
The error I'm getting is that I have an ambiguous reference to member tableView(_:numberOfRowsInSection:)
The rest of my errors in my program so far is 'override can be specified only on class members'
First implement didSelectRow in your WordsTableViewController. Then create instance variable selectedWord. After that, you can get the the selected word in didSelectRow by calling:
selectedWord = myListVocab.vocabWords[indexPath.row]
After assignment, you can use selectedWord in prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowDefinitionSegue" {
if let definitionVC = segue.destination as? DefinitionViewController {
destinationVC.word = selectedWord
}
}
}
Instead of doing it in prepare(for:sender:) push the DefinitionViewController manually in UITableViewDelegate's tableView(_: didSelectRowAt:) method, i.e
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let definitionVC = self.storyboard?.instantiateViewController(withIdentifier: "DefinitionViewController") as? DefinitionViewController {
let word = myListVocab.vocabWords[indexPath.row] //get the word using indexPath...
definitionVC.word = word //set the word in definitionVC's property...
self.navigationController?.pushViewController(definitionVC, animated: true)
}
}
Don't forget to set the Storyboard ID of DefinitionViewController as DefinitionVC in the storyboard.
Also, remove the segue that you created in the storyboard. Otherwise, the DefinitionViewController will be pushed twice unnecessarily.

How to pass the index of the cell in the tableview from one view controller to the next upon pressing a button?

Every time I try to do the following, it passes on the index to the next view controller as being 0. I'm not sure what I'm doing wrong, can someone help? Thank you so much! Here is the relevant code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "a", for: indexPath) as! TableViewCell
cell.useButton.tag = tagBaseValue + indexPath.row
cell.useButton.addTarget(self, action: #selector(ListViewController.useButtonPressed(_:)), for: UIControlEvents.touchUpInside)
return cell
}
#IBAction func useButtonPressed(_ sender: Any) {
performSegue(withIdentifier: "toDisplay", sender: self)
}
func prepare(for segue: UIStoryboardSegue, sender: UIButton) {
if segue.identifier == "toDisplay" {
let nextVC = segue.destination as! NextVC
nextVC.index = sender.tag
}
}
prepare(for is never called because the signature is wrong (the type of sender is Any?)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDisplay" {
let nextVC = segue.destination as! NextVC
nextVC.index = (sender as! UIButton).tag
}
}
and the IBAction must be
#IBAction func useButtonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "toDisplay", sender: sender)
}
Prepare for segue must be overridden, and in button action while sending sender, you are sending the self, which is pointing to viewcontroller itself, hence you are receiving the tag always as 0.
Make changes for prepare for segue, make sender as Any and do overrride it. And in your button action while calling performSegue do mention sender as sender(which is button) and not self(which is view controller).
Hope it helps...

UIViewController's prepare for segue method is not being called

I am trying to pass data from a tableview cell into a tab view controller to be used by the tab view controller's corresponding views. However the overriden func prepare method below is not being called and the program goes to the tab view controller bypassing this method totally.
Storyboard showing the views
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedCarIndex = self.savedCarsTableVC.indexPathForSelectedRow?.row
let destVC = segue.destination as! TabBarController
destVC.selectedCar = savedCars[selectedCarIndex!]
}
I am expecting the selectedCar object to return data from the array however it's nil.
I would try setting the selectedCarIndex in tableView didSelectRow method. Also, make sure you want to be navigating to TabBarController and not some ViewController embedded in the TabBar.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
self.performSegue(withIdentifier: "youridentifier", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedCarIndex = sender as! IndexPath
let destVC = segue.destination as! TabBarController //Are you sure this is the correct ViewController to be casting to?
destVC.selectedCar = savedCars[selectedCarIndex.row]
}

Swift prepare for segue - Send data from one view controller to another

I want to move from one view controller to another and send userId:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("chosenPerson", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId
}
by clicking I get: "fatal error: unexpectedly found nil while unwrapping an Optional value"
what I do wrong?
If you have given segue in StoryBoard DON'T Call this self.performSegueWithIdentifier("chosenPerson", sender: self) method in didSelectItem
If you have given segue in storyboard override func prepareForSegue - this method calls first after that didSelectItem calls
Please refer storyBoard once (below Image for Sample)
I think problem is in self.usersArray[indexPath.row].userId May this returns nil
Swift2:
self.performSegueWithIdentifier("chosenPerson", sender: self)
Swift3:
self.performSegue(withIdentifier: "chosenPerson", sender: self)
Swift2:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
Swift3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destination as! chosenPersonViewController
if let indexPath = collectionView.indexPathForSelectedItem {
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
}
}
When performing the segue, pass the indexPath as the sender and try using this switch statement. If you see "unknown segue" printed out when you select a cell, the destination controller is not of type chosenPersonViewController.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("chosenPerson", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch (segue.destinationViewController, sender) {
case (let controller as chosenPersonViewController, let indexPath as NSIndexPath):
controller.userID = usersArray[indexPath.row].userId
default:
print("unknown segue")
break
}
}
One possible issue could be that in your storyboard you have not set the identifier for your segue to be "chosenPerson". To fix this first make sure you have a segue between your first and second view controllers, which can be created by control dragging one from one view controller to another.
Then make sure the segue has an identifier, specifically: "chosenPerson". To do this: click on the segue between the first two view controllers, then navigate to the attributes tab, and then set the identifier box to be "chosenPerson". Save the storyboard with your changes and now you should be able to call prepareForSegue with that identifier and not experience a fatal error.

Segue is being executed twice

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
self.performSegueWithIdentifier ("Cities", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
Segue is being executed twice leading to the next VC. How can I prevent this from happening?
Delete the current segue in storyboard. Then CTRL-drag from the viewController (not the cell) to the next view controller and name it "Cities". Now, when you select a cell, the didSelectRowAtIndexPath() will fire first and will call performSegueWithIdentifier()
However, if all you're looking to do in the didSelectRowAtIndexPath() is get the row that performed the segue, you can maintain your original setup of having the cell segue from the storyboard, remove didSelectRowAtIndexPath() and in prepareForSegue() do:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = self.tableView.indexPathForSelectedRow {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
}
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
You are the one executing the segue twice — once automatically in the storyboard (because your segue emanates as an Action Segue from the cell prototype), and once in code when you say self.performSegueWithIdentifier. If you don't want the segue executed twice, remove one of those.
Personally, my recommendation is that you delete didSelectRow entirely and move your self.selectedClubState assignment into prepareForSegue.