I want to execute a single line of code when the user selects a cell in my TableView. At runtime, my TableView populates with data okay, and the cells are indeed clickable/selectable. But, when a cell is selected, the 'didSelectRowAtIndexPath method is skipped/not called. I'm new to Swift, so maybe I'm overlooking something very simple. The structure of my code is as follows:
import UIKit
class TopicsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//Number of Sections:
func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2 }
//Number of Rows in Each Section:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) ->Int { return 3 }
//Contents of Each Cell:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
cell.textLabel?.text = "Data"
}
//Code below is skipped/ignored at runtime, no matter what I try:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Hello!")
}
Note: I am not using a gesture recognizer (other threads on this subject suggest a gesture controller could be the culprit)
Did you assign the "delegate" of the tableview?
Related
I have a UITableView nested inside another UITableView.
In the nested tableView, when the user taps on a cell, the cell does highlight, but the delegate method didSelectRowAt indexPath: is not being called.
Other delegate methods are being called, for example methods like willDisplay cell: forRowAt indexPath: or scrollViewDidScroll(_:). So this tells me that the delegates etc. are connected correctly.
In another part of the same application I am using the same kind of structure, UITableView inside another UITableView and there it works fine.
I compared the two extensively, so far I haven't found the difference, and no clue why one should work and the other not!
Please see the implementation of the nested UITableViewCell.
It would be nice if the console would log the line "touch detected".
It does log the lines "scrolling" and "will display cell".
import UIKit
class TestTableViewCell: UITableViewCell {
}
extension TestTableViewCell: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "FileCell")!
}
}
extension TestTableViewCell: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("touch detected")
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("will display cell")
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("scrolling")
}
}
Solution was very simple at last.
I had a UITapGestureRecognizer setup for the outer UITableView.
I had this there to dismiss the keyboard on tap.
After removing the UITapGestureRecognizer it started working fine.
I completely overlooked this, but it's solved now!
I want to add animation when UITableView load cells (From top to Bottom) But getting no idea about this, please someone help me.
Below added a simple table view delegate methode with an array(arrHeader).
Thanks in advance
let arrHeader = ["City1", "City2", "City3"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrHeader.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel?.text = arrSubHeader[indexPath.row]
return cell!
}
Put your animation code in this UItableView delegate method:
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
//TODO: animation code
}
this delegate method is called every time a new or old cell is going to be displayed on the iPhone/iPad screen.
So if you try something in this block with the cells it will reflect on them.
optional func tableView(_ tableView: UITableView,
didEndDisplaying cell: UITableViewCell,
forRowAt indexPath: IndexPath) { }
this method gets called after a cell is being displayed.
Here is the github link for the Example:
Visit: https://github.com/subhajitregor/TableCellCardDropAnimationExample
I have a view controller with a tableview inside that is grouped. This produces a very weird glitch that causes the sectionTitles to show at the side. I've attached top, trailing, bottom, and leading constraints to the superview for the tableview and I've tested returning UITableViewCell() in cellForRowAtIndexPath to see if it was the cell that was causing the problem, but it still shows it like this.
var sectionTitles = ["Customer Orders", "Unprocessed Orders", "Processed Orders"]
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionTitles.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return sectionTitles
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(CONSTANTS.CELL_IDENTIFIERS.ORDER_CELL) as! OrderTableViewCell
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Perform segue to order list in future
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 117.0
}
After hours I figured out that I didn't implement this method
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return sectionTitles
}
If you have only one section you don't put many titles.
If instead you want to give a title for each cell you have to add a label in your customized tableViewCell and in your cellForRowAtIndexPath you have to put something like this (after you have created a NSObject class):
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(CONSTANTS.CELL_IDENTIFIERS.ORDER_CELL) as! OrderTableViewCell
let order = Order[indexPath.row]
cell.yourTitleLabel.text = order.title
return cell
}
Below is the code for my tableView, I have an error on the cellForRowAtIndexPath function declaration that says definition conflicts with previous value. A previous stack overflow question has the solution to make the function return UITableViewCell as an optional value but this does not fix the error for me. I also have an error that says viewController does not conform to protocol UITableViewDataSource, but I assume this is because of the error on the cellForRowAtIndexPath method.
I have similar code for a tableView that works, but it was written about a month ago before I updated Xcode. Maybe a recent change in swift is causing the error?
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell? {
let cellIdentifier = "tableViewCell"
let newCell : TableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! TableViewCell
newCell.heading.text = names[indexPath.row]
return newCell
}
Try placing your datasource methods in a class extension like this:
extension yourViewController: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // cellForRow stuff
}
}
If this is in a UITableViewController, you need to add override to the method:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
Trying to conform to UITableViewDataSource and UITableViewDelegate inside a Swift UIViewController subclass.
class GameList: UIViewController {
var aTableView:UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
aTableView.delegate = self
aTableView.dataSource = self
self.view.addSubview(aTableView)
//errors on both lines for not conforming
}
}
Docs say you should conform on the class line after the : but that's usually where the superclass goes. Another : doesn't work. Using a comma separated list after the superclass also doesn't work
EDIT:
Also must adopt all required methods of each protocol, which I wasn't initially doing.
You use a comma:
class GameList: UIViewController, UITableViewDelegate, UITableViewDataSource {
// ...
}
But realize that the super class must be the first item in the comma separated list.
If you do not adopt all of the required methods of the protocol there will be a compiler error. You must get all of the required methods!
As XCode6-Beta7 releases,
I noticed the protocol method of UITableViewDataSource changed a little bit and sounded the same conform to protocol error which worked fine in beta6.
These are the required methods to be implemented according to the UITableViewDataSource protocol:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // insert code}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // insert code
}
You might want to re-check the difference or re-implement the delegate method that you thought you just implement.
You must implement two require methods here:
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return 10
}
func tableView(tableView:UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
cell.text = "Row #\(indexPath.row)"
cell.detailTextLabel.text = "Subtitle #\(indexPath.row)"
return cell
}
Also, it is important to copy all the non optional functions from the Delegate class. Cmd + Click on the UITableViewDatasource
and copy those two definitions as is.
For me in beta7, the UITableViewDatasource has
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
My implementation:
var items = ["Apple", "Pear", "Banana"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default")
cell.textLabel?.text = items[indexPath.row]
cell.detailTextLabel?.text = "Test"
return cell
}
Usee These methods:
There is change in Data source methods-
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
protocol UITableViewDataSource : NSObjectProtocol {
****func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell****
optional func numberOfSectionsInTableView(tableView: UITableView) -> Int // Default is 1 if not implemented
optional func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? // fixed font style. use custom view (UILabel) if you want something different
optional func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String?
// Editing
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
optional func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
// Moving/reordering
// Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath:
optional func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool
// Index
optional func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]! // return list of section titles to display in section index view (e.g. "ABCD...Z#")
optional func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int // tell table which section corresponds to section title/index (e.g. "B",1))
// Data manipulation - insert and delete support
// After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change
// Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead
optional func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
// Data manipulation - reorder / moving support
optional func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)
}
Ur code will works!!
This question is already answered but just want to make things a bit more Swifty.
Instead of writing protocols in UITableViewDelegate, UITableViewDataSource you can divide them using extensions this will help in organising the code. Adding protocol conformance is described in this page
for the above question, this can be confirmed to protocol using extension:
class GameList: UIViewController {
var aTableView:UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
aTableView.delegate = self
aTableView.dataSource = self
self.view.addSubview(aTableView)
}
}
extension GameList: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
}
extension GameList: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row Clicked at \(indexPath.row)")
}
}