-1

I've created my own CustomTableView and CustomCell. The cell is in a xib, and I'm registering it when initializing the tableView, like this:

[self registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] 
                    forCellReuseIdentifier:kCustomCellIdentifier];

If I don't do this, I won't be able to define what ReuseIdentifier should "point" to this class. This is my cellForRow:

-(UITableViewCell *)tableView:(UITableView *)tableView 
                        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [self dequeueReusableCellWithIdentifier:
                        kCustomCellIdentifier forIndexPath:indexPath];

    if(!cell)
    {
        cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomCell" 
                        owner:self options:nil] objectAtIndex:0];

        cell.delegate = self;
        [cell initialSetup]; //Other stuff
    }
    else
        [cell resetCell];

    //And other awesome stuff

    return cell;
}

This 'works'. When I lauch my app, my own custom cells are showing. However, it turns out the cell is NEVER returned as nil from [self dequeue... Thus, the if-statement if(!cell) is never true. I have additional setup inside this statement that I want to perform, but I don't know where the cell's are being initialized the first time now. If I remove registerNib, then this statement is true, but then it's true for all cells, and none will ever be dequeued.

I can probably work around this, and put my initialSetup (and other stuff) inside the -(id)initWithCoder..-method in the CustomCell-class, but I'd like to know where my cells are being initialized right now. Why do my cells exist before cellForRowAtIndexPath?

Sti
  • 8,275
  • 9
  • 62
  • 124
  • Are you using `storyboard`? – Akhilrajtr Feb 13 '14 at 19:57
  • Then `if(!cell)` will not be true since `dequeueReusableCellWithIdentifier` returns a cell. Use `awakeFromNib` method in `CustomCell` – Akhilrajtr Feb 13 '14 at 20:11
  • @Akhilrajtr But isn't the point of `dequeue..` that I'm re-using my own cells? The way I imagine it is that, at launch - NO cells have been queued. I never made any, so how can they've been queued, right? Then when I scroll 10 rows down, my very first created cell will be queued rather than deallocated, so that I can use it later. When I need the 11th cell, it first checks with this queue by calling `dequeueReusable..`. Since my first cell has been queued, it will be returned here. This makes sense to me. If you guys are saying `dequeue` always return a cell, then I don't understand anything. – Sti Feb 13 '14 at 20:18
  • And all the examples I see everywhere puts `if(!cell)` after `dequeueReusableCell..`. Also, what is the difference for me by using `awakeFromNib` rather than `-initWithCoder`? – Sti Feb 13 '14 at 20:20
  • If there is no existing cell that can be recycled, storyboard will automatically make a new copy of the prototype cell and return it. So the `cell` in `cell = [self dequeue...` will never nil. – Akhilrajtr Feb 13 '14 at 20:26
  • You can find the difference between `awakeFromNib` and `initWithCoder` from [here](http://stackoverflow.com/questions/15508041/should-i-be-using-awakefromnib-or-initwithcoder-here) – Akhilrajtr Feb 13 '14 at 20:35
  • @Akhilrajtr Ok, thanks. So is there a way for me to check in `cellForRow` if `dequeueReusable..` returned a new "automatically made" cell or if it's one of my old cells? – Sti Feb 13 '14 at 20:35
  • 1
    override `prepareForReuse` method of `UITableViewCell` – Akhilrajtr Feb 13 '14 at 20:41

3 Answers3

2

When you register a class or a nib in a table view using method registerClass:forCellReuseIdentifieror registerNib:forCellReuseIdentifier the tableview internally will create an instance of the cell if no one is available when you call dequeueReusableCellWithIdentifier:, so initialization code is no longer needed inside the delegate.

From the UITableView.h code:

// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

Depending of the which register method is used the init methods called are:

  • initWithStyle:reuseIdentifier for cells registered using registerClass:
  • initWithCoder: for cells registered using registerNib:

If you are using registerNib: you can use too awakeFromNib method in the cell, that is also a good place to put initialization code of the cell. The main difference between using initWithCoder: or awakeFromNib its explained in this question.

When a cell is reused, you have the method prepareForReuse in the cell to make some cleanup in the cell and left it prepared to be configured again.

A good approach to work with all of this will be:

//ViewController code

- (void)viewDidLoad
{
    ...
    [_tableView registerNib:[UINib nibWithNibName:@"CellSample" bundle:Nil] forCellReuseIdentifier:@"cellIdentifier"];
    ...
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"cellIdentifier"];
   //configure the new cell, no if (!cell) needed
   return cell;
}


//Cell code

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        //You can put initialization here
    }
    return self;
}


- (void)awakeFromNib
{
    [super awakeFromNib];
    //But is better initialize here
}


- (void)prepareForReuse
{
    //Reuse and reset the cell here
}

Hope it helps

Community
  • 1
  • 1
brovador
  • 31
  • 3
0

When using dequeueReusableCellWithIdentifier: forIndexPath: you don't have to alloc the cell like you would if you were using default UITableViewCell. In your custom UITableViewCell subclass, this is called when it is initialized:

- (void)awakeFromNib {
     [super awakeFromNib];
}

So add that in there and you should be good.

random
  • 8,568
  • 12
  • 50
  • 85
0
- (instancetype)initWithStyle:(UITableViewCellStyle)style
              reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
    //custom your cell
    }
    return self;
  }
  • 2
    Usually it is a good idea to provide some explanation as to why, or how this answers the question in addition to just code. – Makyen Jan 13 '15 at 03:19