Bas
Bas

Reputation: 4551

UITableView method cellForRowAtIndexPath not called

My UITableView isn't showing any data. I think the problem is in:

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell?`

This is my code:

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
    // Configure the cell...
    let cellId: NSString = "Cell"
    var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId) as UITableViewCell

    if let ip = indexPath {
        //var data: NSManagedObject = myList[ip.row] as NSManagedObject
        //cell.textLabel.text = data.valueForKey("name") as String
        cell.textLabel.text = "Hi"
    }
    return cell
}

I've seen tutorials on youtube that use this code, but I can't get it to work.

First I fought it was a problem with my array, but when i just put text in it it still doesn't show anything.

I'm running Xcode6 beta 3, but this code did run perfectly fine in beta 2.

I don't have any warning or error messages.

EDIT: I looked up some other Swift projects of me, I got the same function in there and it worked 2 weeks ago but now it also doesn't work. Maybe this is a Xcode6 beta 3 issue?

My class is of type UITableViewController.

EDIT: I was looking through the Apple developer forums and saw related issues after updating to xCode 6 beta 3, so it's likely a problem with xCode 6 beta 3!

EDIT: The method doesn't get called.

Upvotes: 23

Views: 55121

Answers (18)

Mehdi Ijadnazar
Mehdi Ijadnazar

Reputation: 4951


4 checks to make sure UITableView is displayed properly. I think the last one is the root cause for this question


Apart from misspellings and syntax errors, there are some checks you have to do in order to make sure cellForRowAt will be called and your tableView will be displayed properly:

1. dataSource and delegate

Make sure to properly set the dataSource and delegate objects. Keep in mind that both of these variables are defined as weak references. So they will not be retained. Make sure they do not get deallocated in the wrong place.
This is so rare, but still a possibility. here is an example:
Let's say you create a class to be your dataSource like this :

    class MyDataSource: NSObject, UITableViewDataSource {
        let list = ["Apple", "Google", "Microsoft", "Pinterest", "Amazon"]
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.list.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            // Create cell here
            return UITableViewCell()
        }
    }  

And then assign an instance of this class to your tableView's dataSource when creating it.

    override func viewDidLoad() {
        super.viewDidLoad()

        let dataSource = MyDataSource()

        let tableView = UITableView(frame: self.view.bounds)
        tableView.dataSource = dataSource
        tableView.delegate = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        self.view.addSubview(tableView)
    }

Here Xcode wont complain but your dataSource object will be deallocated after viewDidLoad has finished running, and because tableView does not retain dataSource object it will not call any of UITableViewDataSource function.

2. Cell Class

Register your cell class with proper cell identifier for your tableView

3. numberOfRowsInSection

Make sure to implement numberOfRowsInSection function and return the correct number of rows

4. Layout and Frame

The most important one which is indirectly mentioned in the accepted answer is to make sure that your tableView's frame is not zero. This can happen if you have conflicting constraints in Storyboard or XIB files that prevent AutoLayout engine from correctly calculating the frame of your tableView or its cells. Or it can also happen when you define your tableView programmatically and forget to set the frame or layout constraints for it. UITableView does not call dataSource functions in this case because it does not occupy any space on the screen. Unfortunately, this is not mentioned anywhere on Apple's documentation. However, you can test it yourself.

Upvotes: 0

Markv07
Markv07

Reputation: 276

I just ran into this problem as well. The cellForRowAt was not being called. And the Label inside the tableView kept indicating missing constraints everytime there was a change even after "add missing contraints" over and over again. In this case, the problem was that the tableView was inside a stackView. Once the tableView was relocated outside the stack, the tableView Label missing constraint errors stopped reappearing and the cellForRowAt operated correctly.

Upvotes: 0

Manish
Manish

Reputation: 702

In an interface builder, my screen is designed with table view as landscape mode and I am showing in real device as Portrait mode that is why cellForRow is not being called.

Now, solution for me is that I switched that screen from landscape to portrait in interface build and it worked.

Upvotes: 0

novice
novice

Reputation: 451

I had the same problem weird thing is Numbers of Rows method is getting called but cellForRowAtIndex is not getting called. In my case it is all due to the storyboard constraints and make sure tableiew is not hidden and is installed on the storyboard

Upvotes: 1

user15877964
user15877964

Reputation: 1

You need to set tableview in editing mode in viewDidLoad

tableView.setEditing(true, animated: true)

Upvotes: 0

Mohit Gorakhiya
Mohit Gorakhiya

Reputation: 41

Make sure you hav setup delegate and datasource property for the UITableView object.

Upvotes: 0

Amit Thakur
Amit Thakur

Reputation: 1081

you need to set the height constraint for you table view. You can set in storyboard or programmatically. If you need then i will post a running example.

Upvotes: 0

Rodion Kuskov
Rodion Kuskov

Reputation: 156

Check if you have these lines:

tableView.delegate = self
tableView.dataSource = self

If dataSource = self is not implemented it could be a reason of not called cellForRowAt indexPath method

Upvotes: 7

Bruce Patin
Bruce Patin

Reputation: 2087

override func tableView(_ tableView: UITableView!,
cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { }

I was missing the underscore in as the first parameter tableView.

It also probably needed the override. You will know if you got the func described correctly if the override works.

Upvotes: 0

Satheesh
Satheesh

Reputation: 11276

I had the same frustrating issue when I migrated my old Swift 2.3 code developed in Xcode 8.2.1 to Swift 3.0 in Xcode 8.3, for me numberOfRows was getting called

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return 2
}

but the main data source methods will never get called,

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

The main issue was the UITableView I had created via Swift code was not added to any view, it was added but replaced by another view later so the data source method was never called. Hope it helps someone.

Upvotes: 0

Minh Tường
Minh Tường

Reputation: 409

Maybe you have declare delegate in init:

-(instancetype)init{
self = [super init];
if(self){
    _tableView.delegate = self;
    ,...
    }
return self;

}

Should be call it in ViewDidload:

- (void)viewDidLoad {
[super viewDidLoad];
_tableView.delegate = self;

,... }

Upvotes: 1

kurtanamo
kurtanamo

Reputation: 1828

Got it!

Had the same problem - I also have added a tableview into a uiviewcontroller and it also not worked, but I know the problem now.

If you add the tableview on interface builder AND click after that "Add Missing Constraints", it'll add constraints that can't work together.

At my position I had the tableview on my whole uiview and after click on "Add Missing Constraints", it will add this here:

enter image description here

And now if you delete one of the Trailing or Leading Alignments, it will work - cellforrowatindexPath will get called! Don't know why it is like that, but it will work.

Hope I can help you.

Upvotes: 62

katopz
katopz

Reputation: 671

XCode Version 6.3.1 (6D1002) I'm just run into this issue, In my case is I duplicate UITableViewController and reuse it somewhere cause this problem.

My solution is

  1. Create new UITableViewController
  2. Duplicate only UITableViewCell
  3. Clear all constraints (not sure you will need this but for me it's mess up)
  4. In my case "Add missing constraints" and "Reset to suggestion constraints" is mess up so I manually add it.

Nothing to do with datasource btw, you can simply add some foo content to some label in cell to separated problem.

HTH

Upvotes: 1

Luis Rodríguez
Luis Rodríguez

Reputation: 126

May be this will help you.

I have the following:

self.myTableView.rowHeight = 60
in function heightForHeaderInSection: return 60
cellForRowAtIndexPath is not called

if a value >= 60 is returned in heightForHeaderInSection the cellForRowAtIndexPath is not called.

Even when I set self.myTableView.rowHeight = 59 (or 59 or 58), if I return in heightForHeaderInSection a value >= 60 the cellForRowAtIndexPath is not called.

So, I return a value <= 59 in function heightForHeaderInSection and the cellForRowAtIndexPath is then called. (use breakpoints in cellForRowAtIndexPath to check this).

Another issue: If cellForRowAtIndexPath is called but you don´t see the rows of your tableView: This is because the height of your tableView is too short.

For example: (in this case titulo_tabla is a UILabel that I have above my table. aOrdenes is an NSArray from which I get the count of rows that I show).

var width = self.view.frame.size.width
var height = self.view.frame.size.height
... 
myTableView.frame = CGRectMake(width * 0.03, titulo_tabla.frame.origin.y + titulo_tabla.frame.height, width - 2 * (width * 0.03), 60.0 * CGFloat(aOrdenes.count) + 50)

In the last code, the last parameter ..., 60.0 * CGFloat(aOrdenes.count) + 50) the 60 is the rowHeight (self.myTableView.rowHeight = 60) and the 50 is the value returned in function heightForHeaderInSection. With this your tableView rows are showed.

Upvotes: 1

Akshay Degada
Akshay Degada

Reputation: 1

I was also having that problem on UITableView, I also set the data source and delegate to the table view but my cellForRowAtIndexPath method was not called.

Solution:

  • my network blocked my method (by using firewall). I asked my network admin, and I was given full access to the network, and then my cellForRowIndexPath method was called.

  • when my response comes from a web service, due to network block response was black so, cellForRowIndexPath method was not called.

Upvotes: -3

Bas
Bas

Reputation: 4551

Seem's that there isn't a solution for this. Returned to xCode 6 beta 2 fixed the issue. Hopefully and likely it will get patched in Beta 4.

Upvotes: 1

vacawama
vacawama

Reputation: 154523

You need to implement this or cellForRowAtIndexPath will never be called:

override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
  // Return the count of the number of rows in the table
  return 5
}

The 5 is just an example of course. You would return the count of the number of elements in your array.

Upvotes: 12

artey
artey

Reputation: 1243

You must make sure that the datasource is correctly assigned and that you use the correct method signature. You declared some optionals wrong.

func tableView(tableView: UITableView!,
cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { }

Upvotes: 0

Related Questions