Trouble Selecting Table View Rows - ios

I am having trouble selecting table view row in didSelectRowAt/didSelectRowAtIndexPath. The function is never called.
func tableView(tableView: UITableView, didSelectRowAt indexPath: NSIndexPath) {
print("Row: ", indexPath.row)
if(indexPath.row == 9)
{
print("Row 9 Selected")
}
}
Based on various Stack Overflow articles, here is what I have tried:
I have tried "didSelectRowAt" and "didSelectRowAtIndexPath"
I have set the table view's delegate to self using its outlet
Table View Settings:
-Selection: Single Selection
-Editing: No Selection During Editing
-Interaction: User Interaction Enabled
Individual Cell Settings:
-Interaction: User Interaction Enabled
I set tableview.allowsInteraction to true in code as well as storyboard

Should be with _
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Check Docs

The problem was that I was using NSIndexPath instead of IndexPath

check delegate value using break point either it is nil or not
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Code
}

You have to set an #IBOutlet to the tableView in you ViewController and set as it's delegate and dataSource.
Something like this :
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
And implements the UITableViewDataSource protocol too.
Or you can too in the Interface Builder set the ViewController as it's delegate and dataSource and avoid to set manually in code like above.
If you have more than one tableView I your code than please try to mention different names for every tableView and then call the delegate with particular tableView name.
Also you have mentioned 3rd point here “Single Selection -Editing: No Selection During Editing”. This means if you try to edit anything in tableView there will be no selection please try to replace this and then check if you get some result.
Because if set “tableView.allowsSelectionDuringEditing = false” then it will not allow you selections in tableView.

Related

My TableView datasource functions aren't being called and I don't know why

So I have a UITableView, the kind you drag into a view controller, not a tableviewController. I set the delegate property to self in the viewDidLoad:
searchTableView.delegate = self
searchTableView.isHidden = true
searchTableView.isUserInteractionEnabled = false
I added a prototype cell to it in storyboard with the identifier "SearchResultCell". Here's my tableview data source functions:
extension MapViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
searchCompleter.queryFragment = searchBar.searchTextField.text!
let completionResults = searchCompleter.results
return completionResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
searchCompleter.queryFragment = searchBar.searchTextField.text!
let completionResults = searchCompleter.results
print(completionResults)
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchResultCell", for: indexPath)
cell.textLabel?.text = completionResults[indexPath.row].subtitle
return cell
}
}
Literally none of the code in these functions is being called. (Don't worry, the isHidden and isUserInteractionEnabled functions get switched before I called the table view functions, so that's not the problem)I think I'm somehow not connecting these functions to my specific UITableView, but I don't know what else to do aside from set the delegate to self which I've already done. Any suggestions as to how I can get these to be called are much appreciated!
Here is a picture of my view controller so you can see if the lack of constraints or positioning are an issue:
also You need to add
searchTableView.dataSource = self
You can also set both connections in the storyboard
but then, I think you have another problem - which is that I don't think you can have a UITableView embedded in a MapViewController - here's a discussion about someone else with the same issue Implementing UITable in MapView
I think your solution will be to use a UIViewController which contains both a Map and a Table - you can make it look identical to what you already have.
Make sure completionResults.count not equal 0.

TableView empties when interacting

So I have 2 Views that are shown inside a UIView, based on what is selected on the SegmentViewController. I create dummy data, returning 20 row of a custom cell. This works great.
Everything is fine, till I interact with the TableView.
Bellow is my code:
GoalsViewController.swift
import UIKit
class GoalsViewController: UIViewController {
#IBOutlet weak var goalsTableView: UITableView!
let goalCellIdentifier = "goalCell"
override func viewDidLoad() {
super.viewDidLoad()
goalsTableView.delegate = self
goalsTableView.dataSource = self
goalsTableView.register(UINib(nibName: "GoalsViewCell", bundle: nil), forCellReuseIdentifier: goalCellIdentifier)
goalsTableView.reloadData()
}
}
extension GoalsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = goalsTableView.dequeueReusableCell(withIdentifier: goalCellIdentifier, for: indexPath) as! GoalsViewCell
cell.goalTitle.text = "aaaaa"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected \(indexPath.row)")
}
}
After any of the empty rows is selected, the didSelectRowAt is not called, so the cells are not there at all. I tried to find a solution, but I was only to find issues about empty lists, before being populated.
What could be the reason for the empty tableview?
I might be wrong here but one thing that I've noticed is that you are not implementing a function which sets the height of each cell.
// Specify the height of your cells
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100 // Or your given cell height.
}
So here is my theory: If you are using constraints something is missing and your cell's height can't be identified by constraints alone or you are not using constraints at all thus you must use heightForRowAt function to specify each cell's height.
I will explain what was the issue for people who probably did not know (like me).
So my UITableView is inside a UIView that changes based on what the user is selecting. In total I had 2 different Views that where switching. The reason that it was emptying it was because my parent ViewController, could not access the delegate for UITableView. To fix that, after adding a subview to the UIView, you need also to move the ViewController to the parent controller. In code it goes like this.
// Empty array of UIViewControllers
var views: [UIViewController]!
// Add the UIViewControllers to the array
views = [UIViewController()]
views.append(EventsViewController())
views.append(GoalsViewController())
for view in views {
// Needed to adjust the size of Subview to size of View
view.view.frame = containerView.bounds
// Add the subviews
containerView.addSubview(view.view)
}
// Bring the view in position 1 to the front of the UIView
containerView.bringSubviewToFront(views[1].view)
// Add Views[1] UIViewController as a child to the parent controller
self.addChild(views[1])
views[1].didMove(toParent: self)
// After done with everything with the UIViewController remove it
views[1].removeFromParent()
addChild Apple.com
didMove Apple.com

didSelectRowAt Swift 3 Not Called even after delegate and dataSource are set

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.

I am trying to call the tableview "editActionsForRowAtIndexPath" method in a button action. the editing view is not showing

You can see my code here:
#IBAction func edit(sender: UIButton?) {
let indexPath = NSIndexPath(forRow: 0, inSection: 1)
self.tableView(tableVw, editActionsForRowAtIndexPath: indexPath)
}
It seems to that you miss the key points of UITableView behaviour. Please consider to read official documentation first: https://developer.apple.com/reference/uikit/uitableview
You got it backwards, the
optional func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
function is called by the table view on it's delegate while you are supposed to implement it and return an array of custom actions you want displayed - it's not supposed to be called by you to signal something to the table view.
https://developer.apple.com/reference/uikit/uitableviewdelegate/1614956-tableview

Swift UITableView didSelectRowAtIndexPath not getting called

New to IOS development and am having trouble with handling cell selection on a table. Whenever I select, the method is not getting called below - any idea why?
My project structure is:
View Controller -> View -> Table View
The below code demonstrates the method calls. The others get called no problem! I know touch is working as pull down successfully refreshes and on clicking a cell it does become highlighted.
import UIKit
class ViewController: UIViewController, UITableViewDelegate
{
let blah = ["blah1"]
//How many sections are in the table?
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//How many rows? (returns and int)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return blah.count
}
//table contents for each cell?
//Each time this is called it'll return the next row and thus build a table...
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("Populating each cell of table view!\n")
tableView.rowHeight = 80.0
var cell = UITableViewCell()
var(a) = blah[indexPath.row]
var image : UIImage = UIImage(named: a)!
cell.imageView.image = image
return cell
}
//Code Cell Selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
println("You selected cell #\(indexPath.row)!")
}
func tableView(tableView: UITableViewDelegate, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
print("wananananaanan" )
println("You deselected cell #\(indexPath.row)!")
}
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.
}
}
Everybody is mentioning to set dataSource and delegate of the tableView.
But after setting also not working fine then sometimes it may happen because of none or disable selection of table view.
To enable it
Go to storyboard -> Select tableView -> click on the attribute inspector ->go to selector -> Select selection as single selection (or multiple selection according to the requirements.)
Please find attached screenshot for your suitability.
You have to set an #IBOutlet to the tableView in you ViewController and set as it's delegate and dataSource to you can see the data an respond to changes in the tableView.
Something like this :
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
And implements the UITableViewDataSource protocol too.
Or you can too in the Interface Builder set the ViewController as it's delegate and dataSource (more easy to do I think) and avoid to set manually in code like above. Is up to you.
I hope this help you.
SWIFT 3
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Do here
}
Use the above delegate method in swift 3
Couple of checks that can help you:-
myTableView.allowsSelection = true
myTableView.delegate = self
Make sure you written didSelectRowAt correctly:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
If you are using UIButton on UITableViewCell then it overlaps cell so check Solution here
I faced the same issue when compared two identical code examples where one was working well and the other was not calling didSelectRowAtIndexPath
Take a look at two possible ways to solve the issue:
1) In the code itself:
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
table.delegate = self
table.dataSource = self
//data source might be already set if you see contents of the cells
//the main trick is to set delegate
}
2) Using Storyboard or Document Outline (which was the problem in my case cause storyboard changes are not visible in .swift controller classes.
Open Document Outline and Control + Press your TableView
you will see two outlets called "delegate" and "dataSource"
drag them 1 by 1 to the containing ViewController (right onto the yellow circle)
That's it!
Another caveat is tap gesture recognizers. It's a common use case to use tap gesture recognizer to handle different logic within your view controllers with table views, whether that's exiting touch control or first responders.
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
view.addGestureRecognizer(tapGesture)
E.G. This line of code handles dismissing a date picker in my application and prevents my tableview from calling didSelectRow delegate method
You have to use this: First take a look what are you extending and then use the tableView method.
class YourViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var mUITableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// We need to tell to UITableView that we will add the data by ourselves
self.mUITableView.delegate = self
self.mUITableView.dataSource = self
// Register the UITableViewCell class with the tableView
self.mUITableView?.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.cellIdentifier)
// Setup table data
getEvents()
self.mUITableView.allowsSelection = true
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// here to create you cell view
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "subtitleCell")
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
cell.textLabel?.text = "\(tableData[indexPath.row].name) - (\(tableData[indexPath.row].eventStateId))"
cell.detailTextLabel?.text = tableData[indexPath.row].lastUpdate
return cell
}
}
Another reason you may write this function which allowed to click under condition
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if(indexPath.section == 1){
return true
}
return false
}
Another caveat which took me ages to figure out is to make sure that all three of your Table View, your Cell and your Content View all have User Interaction Enabled. Then in Swift 4, at least, you can use:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
if you are editing your tableView:
tableView.allowsSelectionDuringEditing = true
Another thing to check is the access level for your class & method:
I had a Swift UIViewController class marked #objc public, to make it visible to my objective-c code.
In this context you must add public access to this function, or it will not be called.
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Nothing happened till I've cleaned and built again. :)

Resources