34

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.
  }
}
Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
Mark
  • 587
  • 1
  • 7
  • 13

13 Answers13

111

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 attachment

Please find attached screenshot for your suitability.

Himani Sharma
  • 1,550
  • 2
  • 10
  • 12
  • 2
    yes I disabled it first (by setting Selection to None in Storyboard) to focus on implementing the list with custom cells, once I started working on the navigation I forgot I had disabled it, took me a while to find the option highlighted in this answer.. – Samuël Jul 08 '19 at 08:28
44

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.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • Or instead of subclassing `UIViewController`, use `UITableViewController` - then you get a lot of functionality for free. For example the `UITableView` will be already setup for you with the delegates pointing to your view controller. – Stefan Arentz Mar 15 '15 at 19:52
  • Thank you, that worked perfectly! (I went with the quick option of setting the View Controller as delegate outlet. – Mark Mar 15 '15 at 22:02
  • the `.delegate = self` completely resolved this issue for me. I'm suprised that I did not do this before. Looks like table views can pack tons of features without setting this delegate value. – Matt Andrzejczuk Dec 27 '15 at 00:17
  • Fellow Googlers: You must pass in `UITableViewDelegate` in your class declaration to get `.delegate` to work!! For example, my class is called `PickFavVC`. This is what I have in `PickFavVC.swift`: `class PickFavVC: UIViewController, UITableViewDataSource, UITableViewDelegate {` – velkoon Dec 07 '18 at 02:29
18
  • 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

Jack
  • 13,571
  • 6
  • 76
  • 98
  • 1
    After Googling like 30 mins or something, you just saved me! And the problem is that I have set the `myTableView.allowsSelection = true` when creating my table view, Thanks! – Joshua Aug 17 '21 at 08:11
  • 1
    @konekoya glad i could help – Jack Aug 17 '21 at 09:26
16

SWIFT 3

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      // Do here
    }

Use the above delegate method in swift 3

Lineesh K Mohan
  • 1,702
  • 14
  • 18
8

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!

Ivan V
  • 3,024
  • 4
  • 26
  • 36
6

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

Mochi
  • 1,059
  • 11
  • 26
2

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
    }
}
Hugo
  • 1,106
  • 15
  • 25
Victor Ruiz.
  • 1,706
  • 22
  • 22
2

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
}
Ahmed Safadi
  • 4,402
  • 37
  • 33
2

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)
1

if you are editing your tableView:

tableView.allowsSelectionDuringEditing = true
Tatarasanu Victor
  • 656
  • 1
  • 7
  • 19
0

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)
Chris Deft
  • 206
  • 2
  • 9
0

Nothing happened till I've cleaned and built again. :)

Yizhar
  • 875
  • 9
  • 11
0

In my case, I had editing set to true on viewDidLoad.

tableView.isEditing = true

Setting it to false or removing it, allowed didSelectRowAt to behave normally again.

GIJoeCodes
  • 1,680
  • 1
  • 25
  • 28