I am relatively new to Swift/Xcode and I am trying to make a view controller appear with different values when a button is selected (an add button) or a table view cell is selected (which allows them to edit). However, I am unable to get any response upon the selection of my row including a print statement I have put in for testing, although the segue does function when I link the transition to a button. The code is identical to that of a functioning table view cell I wrote previously that makes the current table view appear. Could this be an issue with the storyboard?
Storyboard screenshot with cell settings
Here is my code:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
cell.textLabel?.text = items[indexPath.row].name
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Selected")
}
//Sends current receipt information to the AddItemViewController display when tapped
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "AddItemViewSegue" || segue.identifier == "EditItemViewSegue" {
let destination = segue.destination as? AddItemViewController
destination?.currentReceipt = currentReceipt
let index = tableView.indexPathForSelectedRow?.row
print("test")
if segue.identifier == "AddItemViewSegue" {
destination?.addMessage = "Add a New Item to Your Receipt"
destination?.buttonMessage = "Add Item"
}
else {
print("test1")
destination?.addMessage = "Edit an Item in Your Receipt"
destination?.buttonMessage = "Edit Item"
destination?.currentItem = items[index!]
}
}
}
I have also looked into this forum post because it is similar to mine but I was unable to apply any of the suggested fixes.
https://developer.apple.com/forums/thread/14842
First of all the didSelectRow method is wrong. The code is Swift 2 code. The proper signature is
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { ...
Didn't you wonder why the compiler doesn't complain about the missing override?
Rather than from the view controller reconnect the segue (why are there 2 ones?) from the table view cell to the destination controller and delete didSelectRow
Related
I'm working on a personal project and I want to make the cells in my UITableView clickable, such that when they are pressed they segue to the next view, and pass information from their cell along with it when they are pressed.
I've attempted to look over other guides and videos that demonstrate how to do this, however they are all outdated. One that stood out to me that seemed to show promise but didn't end up working was in reference to a certain "didSelectRowAt" function, but I could not get this to work.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as!
CandidateTableViewCell
if (indexPath.row >= candidateCells.count){
print("???")
candidateCells.append(cell)
print("Strange error")
}
tableView.delegate = self
cell.CandidateName?.text = candidatesNames[indexPath.item]
cell.CandidatePos?.text = candidatesPositions[indexPath.item]
//cell.candidateButton.tag = indexPath.row
cell.CandidateName.sizeToFit()
cell.CandidatePos.sizeToFit()
print(candidateCells)
print(indexPath.row)
print(candidateCells.count)
print(indexPath.row >= candidateCells.count)
candidateCells[indexPath.item] = cell
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "Segue", sender: Any?.self)
}
What I was expecting to happen was that the cell would become clickable, and when the cell is clicked it would send me to the next page in the app, however when clicked, nothing happens. The cell does not become highlighted, and the segue does not occur. Thank you so much for any and all suggestions!
If you want to pass information to the next cell, I usually avoid using a Segue, and setup the ViewController with a reuse identifier. By doing this, you can pass information easier. For instance
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "YOURRESUEIDENTIFIER") as! YOURVIEWCONTROLLERCLASS
vc.infoToPass = cellData[indexPath.row]
DispatchQueue.main.async {
self.navigationController?.pushViewController(vc, animated: true)
}
}
Your other option would be to implement the shouldPerformSegueWithIdentifier() method in order to set the data properly. You would click your cell, which calls the performSegue function, which would call the shouldPerformSegueWithIdentifier where you can set the data and return true
I've searched around and haven't truly found why this is happening. Basically, I followed this tutorial https://www.youtube.com/watch?v=yupIw9FXUso by Jared Davison on creating Table View Cells to Multiple View controllers. In his example, everything works perfectly, but for some reason when you click on a table view cell in my code the cell is highlighted in grey. Then, when the user clicks on a separate table view cell the view controller that should have been loaded by the first table view cell is loaded. If the user then clicks back on the original table view cell the page that should have been loaded by the second table view cell is loaded. In summary, all of the view controllers are loaded a "click" behind.
Here is the code for the table view:
//Feed Navigation Functions
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "feedCell") as! FeedTableViewCell
cell.txtTitle.text = "The Fight Against \(elements[indexPath.row])"
cell.issueIcon.image = UIImage(named: "Issue Icons_\(elements[indexPath.row])")
return cell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
Update: The array is a simple array of strings for example [One, Two, Three] there are 6 strings in the array.
When you select a cell then select another one the method didDeselectRow is called so the Vc is pushed you actually want to implement didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
// this to deSelect it after push
tableView.deselectRow(at: indexPath, animated: false)
}
This method fired when a cell is selected
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath
This method fired when a cell is deSelected
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath
You want to use the tableView's delegate method didSelectRow instead of didDeselectRow I think...
Issue: click on a table view cell in my code the cell is highlighted in grey
This is due to the selectionStyle, which you can read about here. If you don't want the cell highlighted, you can set cell.selectionStyle = .none.
Edit: As indicated in other correct response - issue was with incorrect/typo in method - we should use didSelectRowAt not didDeselectRowAt.
This question seems to have been asked many times on StackOverflow, but after searching for hours, I still haven't found the solution to my issue.
I have a table view in SecondViewController.swift and I did make it delegate and dataSource SecondViewController.swift, but the didSelectRowAt method is still not fired when a table cell is clicked. I am trying to apply a segue to another view controller, but the didSelectRowAt method isn't working itself.
I have selected Single Selection in my storyboard in the table view properties, and I have made sure that user interaction is enabled for the table view and the prototype cell.
For the SecondViewController.swift below, please assume that allEvents are populated into the allEvents array. I was able to successfully populate them and display them in the table. The only problem is clicking on the row to perform a segue. Also, please ignore the awkward indentation below.
SecondViewController.swift
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
var allEvents: Array<JSON> = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//self.tabBarItem.image = myTabImage
self.tabBarController?.tabBar.isTranslucent = false
self.tabBarController?.tabBar.barTintColor = UIColor(red:0.25, green:0.25, blue:0.25, alpha:1.0)
self.tabBarController?.tabBar.tintColor = UIColor.white
//ASSUME ALL EVENTS ARE POPULATED INTO allEvents
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Tableview Datasource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allEvents.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("SEGUE")
self.performSegue(withIdentifier: "oneSegue", sender: allEvents[indexPath.row])
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "eventViewTableCell", for: indexPath) as! EventViewTableCell
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// let detailController = segue.destination as! EventDetailsController
}
}
I have been on this for hours and still have not found out the problem. I would greatly appreciate any help!
You may want to check your tableview again, do choose single selection.
I'm assuming you are selecting No Selection as the picture bellow
Hope it helps.
I had the same problem on a Controller within a TabBarController.
What fixed it for me was this:
Disable the User Interaction for the Content view
My guess is that it was becoming the responder so it removed the event from the TableView
Note: Since the viewDidLoad assignments to delegate and dataSource became redundant after setting it up in the StoryBoard, I removed them, although leaving them does no harm.
If you do nothing else than calling the segue in didSelectRowAt remove the entire method and connect the segue in Interface Builder to the table view cell (rather than to the controller). The sender parameter will contain the reference to the selected table view cell.
I suspect when you collected and populated your allEvents array did you collect any touch events in there ?
or have you used UIGestureRecognizer in this or it's super view ?
If you have intercepted any touch event to populate your array or any other purpose comment it out and test it with a simple preloaded array like :
let dataSource = ["1", "2", "3", "4"]
let me know if this is not your case so I can find another solution.
How can I make a static table view to create an action when one of the cells is clicked in Swift?
I have created a static table like a general menu of the app, I can directly create a push segue when one of the cells are clicked. But at the same time when I click to one of the seques, I want the below function to be run. By draging a cell to the UITableView in storyboard the create action option is not appearing.
var goToProfiles = PFObject(className: "goToProfile")
goToProfiles["user"] = PFUser.currentUser()!.username
goToProfiles["goToUser"] = usernameLbl.text
goToProfiles.save()
If you use sections you will also need to query them.
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(indexPath.section)
print(indexPath.row)
if indexPath.section == 1 && indexPath.row == 1 {
// do something
}
}
I found the solution with the code below:
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 1 {
//here you can enter the action you want to start when cell 1 is clicked
}
}
For swift 3 compatibility:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Your action here
}
I created a table view where the user is able to add rows by clicking an "add" button in navigation bar. When the user selects a row the app shows another table view. I want to set the title of the navigation bar to the name of the selected row.
I know how to set the title of the navigation bar if I pass the name to label in the second table view.
title = self.restaurant.name
But I haven't figured out how to pass it to the navigation bar without creating a extra label.
It's actually really easy. All you have to do is implement prepareForSegue and use sender to create an instance of UITableViewCell. From there you can easily get the title of that cell and using segue.destinationViewController you can set the nav bar title of the subsequent view controller.
import Foundation
import UIKit
class TableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CellID", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "Cell at row \(indexPath.row)"
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as UIViewController
let cell = sender as UITableViewCell
destinationVC.navigationItem.title = cell.textLabel?.text
}
}