3
votes

I have a UITableView as a subview in a UIViewController. I'm not using UITableViewController because I have some other content that is not tableview-related taking up part of the screen. I am using storyboards. I have the tableview set up as an outlet, with the viewcontroller being the datasource and delegate. If I use the standard UITableViewCell in this scenario, everything works well and I can load content.

I need to use a custom UITableViewCell for this tableview, so I performed the following steps:

  1. Created a UITableView subclass named SWTableViewCell
  2. Added a call in viewDidLoad to register the cell with interface builder: [self.tableView registerClass:[SWTableViewCell class] forCellReuseIdentifier:@"Cell"];
  3. In the storyboard on my tableview, set the prototype cell's Class to SWTableViewCell
  4. In the storyboard, set the cell reuse identifier to "Cell"
  5. Added some labels to the prototype cell on the storyboard
  6. Still in the storyboard, ctrl-dragged from the labels to the SWTableViewCell.h to create outlets
  7. In my cellForRowAtIndexPath: method, dequeue and cast the cell to the custom subclass: SWTableViewCell *cell = (SWTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"Cell"];

The cell variable is the proper type when I check it. It's not a UITableViewCell, but a SWTableViewCell. But none of the outlets are populated. The properties exist, but they are nil. I'm sure there's a connection I must be missing, but i can't think of anything I skipped at this point.

Is this scenario possible, or does it just not work via IB and storyboards?

2
who is the file owner of your cell ? - Basheer_CAD
I don't see why it wouldn't work, I'm testing it with a blank project, I'll let you know - rdurand
Looks like removing registerClass:forCellReuseIdentifier: makes it work. I'm looking into why. - rdurand
@rdurand wow, just worked for me too. If you write this up as an answer, I'll accept it. Wonder what the reason is. That would be interesting to know. - Mark Struzinski
@MarkStruzinski : I'm looking into it. I've never used registerClass:forCellReuseIdentifier:, so I don't know how it's supposed to work. I'll write an answer and update it as I find info on this. - rdurand

2 Answers

8
votes

Removing the call to

[self.tableView registerClass:[SWTableViewCell class] forCellReuseIdentifier:@"Cell"];

solves the issue.

I don't know exactly what this method does as I've never used it, so I'll look into it. If anyone has information on wether or not this call is required for something, please tell us !


Edit :

So, the idea behind registerClass:forCellReuseIdentifier: is that it tells the tableView how to create new cells. That way, if dequeueReusableCellWithIdentifier: does not return a cell (if the queue is empty), the tableView knows how to create a new cell, and you don't need to manually create one).


Edit 2 :

I found this thread, in which it says :

If the cell is created using prototypes within a storyboard it is not necessary to register the class.

Simply calling dequeueReusableCellWithReuseIdentifier: will "activate" the cell reusing functionality of your tableView.

So registerClass:forCellReuseIdentifier: is to be called only if you manually build your cells, without the use of storyboards.

4
votes

Here are some tips:

Basically there can be 3 ways to create and use UITableViewCells:

  1. Use “prototype” cells in the storyboard/nib

    (Create cell UI in the storyboard/nib inside UITableView)

    You should not use either registerClass:forCellReuseIdentifier: or registerNib:forCellReuseIdentifier: methods. UIStoryboard handles it on its own, since you specified the reuseIdentifier in the storyboard, the tableView knows which cell is associated with which reuseIdentifier.

  2. Use a separate nib for tableViewCell UI

    (This might be a way to go when you want to use the same tableViewCell in several tableViews)

    You should use registerNib:forCellReuseIdentifier: method.

  3. Do not use nibs, create tableViewCell UI programmatically

    You should use registerClass:forCellReuseIdentifier: method.

Also, note that both registerClass:forCellReuseIdentifier: and registerNib:forCellReuseIdentifier: should be called before (most often in viewDidLoad) dequeueReusableCellWithIdentifier:forIndexPath:method is called. If you registered a class or a nib for the reuseIdentifier it is guaranteed that dequeueReusableCellWithIdentifier:forIndexPath: returns a valid cell (unlike dequeueReusableCellWithIdentifier:).

In your code Storyboard registered a nib with UI for the cell, but you calling registerClass:forCellReuseIdentifier: with the same reuseIdentifier forced table view to unregister the nib and register the class which was not aware of IBOutlets.