This question already has answers here:
UITableView didSelectRowAtIndexPath: not being called on first tap
(16 answers)
Closed 7 years ago.
So here's my strange problem.
I have a small app which uses storyboard.
I have 1 UITabBarController which has 2 tabs:
- 1 UITableViewController(subclassed)
- 1 UIViewController(just has a UILabel and does nothing till now)
The UITableViewController is subclassed and i provided:
- numberOfSectionsInTableView(tableView: UITableView) -> Int
- tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
- tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
- tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
The tableview has 2 sections (7 and 1 row).
The rows in section 1 are custom cells and should do nothing when selected.
The row in section 2 is a standard UITableViewCell and should start a download.
But When i selecting any cell tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)isn't even called, only after selecting another cell(not the same again), the didSelect will be called with the first cell i selected.
Another example; (x,x) is representing the selected indexPath
(1,0), does nothing -> (0,6), (1,0) is selected -> (0,2), (0,6) is selected -> (1,0), (0,2) is selected
Additions:
- The highlighting is working as it should. Just the call of tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) isn't.
- tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? is called appropriate.
Solution:
Was a little typo in the delegate method. I implemented didDeselectRowAtIndexPath instead of didSelectRowAtIndexPath
You are calling didDeselectRowAtIndexPath instead of didSelectRowAtIndexPath.
You should use this method :
tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
Please check your delegate method, it should be;
tableView(tableView: UITableView, selectRowAtIndexPath indexPath: NSIndexPath)
Related
I get this error message: failed to obtain a cell from its dataSource
The strange that
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
not even get called, problem is not that returned cell is nil. I put in breakpoints. cellForRowAtnot get called.
numberOfRowsInSection returns value.
I do not know it is relating or not, but now I do not use UITableViewController, I just have a UIViewController, and it is the datasource and delegate for the UITableView. I hope it can not cause interfere. Any idea?
Cross check below check list:-
it's because you are failing to dequeue a reusable cell.
The problem is that your cellForRowAtIndexPath function is embedded in another function
when you forgot to add the UITableViewDataSource and UITableViewDelegate protocols to the ViewController declaration.
class DataViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
I guess this is your problem - Failed to obtain a cell from its DataSource
you can take a look at: https://www.hackingwithswift.com/example-code/uikit/fixing-failed-to-obtain-a-cell-from-its-datasource
try something like this:
cell = tableView.dequeueReusableCellWithIdentifier(getCellIdentifierForType(cellType))
setDataToCell(cell, item: item)
good luck
Please make sure when you are migrating your code from swift older to new versions then your tableview data source and delegates have updated syntax.
For example
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
and
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Can not auto updated to below:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
I have some questions with Swift 3 function calling. Below is an example.
Old Swift:
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell
Swift 3:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
That's fine with the above syntax. But now Xcode shows me an error and asks me to do like below:
#objc(tableView:cellForRowAtIndexPath:) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
I do not understand why I have to declare #objc(tableView:cellForRowAtIndexPath:).
This is happening only when I am trying to implement table view datasource methods under an extension. Also this is not happening for numberOfRowsInSection or viewForHeaderInSection.
Can anyone help me to understand why this is happening?
While I am not sure what triggers the #objc, I can suggest the following approach:
Store the tableView variable somewhere in the viewDidLoad:
let tv = tableView!
Then hover over the tableView variable and press the command button in conjunction with a click.
This should take you to the interface of a UITableView.
Then, hover over either UITableViewDelegate or UITableViewDataSource and press the command button in conjunction with a click.
Now you can see the new signatures.
A lot has changed...Happy upgrade!
Swift compiler forced to write Objc(funcName) before function if you are using this function from Objective c. According to app doc
Use the #objc(name) attribute to provide Objective-C names for
properties and methods when necessary. For example, you can mark a
property called enabled to have a getter named isEnabled in
Objective-C like this:
var enabled: Bool {
#objc(isEnabled) get {
// ...
}
}
To void this, use extension to write TableView Datasource and delegate
extension YourViewControllerName:UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell() as SplitAddContactCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int)
is getting called and returning non zero value.
but the following code isn't getting called.. why?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
tableView is initially 0 size, and supposed to grow dynamically, would it be the cause of this?
cellForRowAtIndexPath will not be called if tableView's size is zero!
And you must not keep any logical part in that method. You must use that method only for updating the ui, no more.
i am fresher and i am doing my app in swift language and i want to know that what is the difference between
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell?
and
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell/
delegate methods in UITableView?
As a one line answer to the question,
The first method
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell?
is not tableView delegate method. It an instance method in UITableView Class. Which is used to get a cell from tableView instance by passing indexPath as parameter. So you will be using this method on a tableView instance.
The second method
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
is the datasource method of UITableView that is used to populate tableview cells. This method will be implemented in the datasource/delegate class.
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell? is a UITableView method, it is used to get a cell at a given time when the tableview is defined. For instance, it can be used to check is a cell is visible. If it is not visible this method will return nil.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell is a UITableViewDataSource method, it is used to define all the cells of the tableview, so that it can know what to display.
The first method
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell?
It is an instance method in UITableView Class. And it is used to get a cell from tableView instance by passing indexPath as parameter .
and the second one
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
is the datasource method of UITableView and it is one of the require method in UITableView.
Thank you.
I have the following code
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = users[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
var cell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
}
The purpose was to show a checkmark when a row is tapped. Have two rows and I am observing the following behavior.
Tap row 0, can't see the checkmark
Tap row 1, can see the checkmark for the row 0
Tap row 0, can now see the checkmark for row 1
The selection attribute settings are (Xcode default)
Selection: Single Selection
Editing: No selection during editing
Is there anything I should do to show the checkmark when the row is tapped in addition to the above code. Looked into related questions but couldn't nail it.
This is a very common problem, I think almost everybody who does iOS programming has faced the same.
You need to change
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
to
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
The issue is with the XCode suggestions as one types the UITableView delegate methods. Since deselect comes first alphabetically, it is a very common mistake. I used to face this issue with Objective C, it's funny to see this problem arising with Swift as well.