So I have a custom uitableviewcell and I have code that looks like this in the cellForRowAtIndexPath method
defaultCell = [self.listView dequeueReusableCellWithIdentifier:DefaultCellIdentifier];
if(defaultCell){
defaultCell = [[DefaultCell alloc]init];
}
The if is passed and the default cell is alloced and inited. However, the cell shows up to be blank (the xib file isn't there). I'm registering the nib with the tableview like this -
UINib* defaultNib = [UINib nibWithNibName:#"DefaultCell" bundle:nil];
[self.listView registerNib:defaultNib forCellReuseIdentifier:DefaultCellIdentifier];
So why am I getting a blank view in my table cell instead of what I see in my xib file? I think it's because I'm not allocing the cell with it's xib.
What's going on?
This call is wrong for two reasons:
if(defaultCell){
defaultCell = [[DefaultCell alloc]init];
}
Firstly, it should be if(!defaultCell)
Secondly, don't even need to check if a cell was dequeued if you've registered a nib for it. dequeueReusableCellWithIdentifier will always return a cell in this case. All you need to do is configure it.
So, actually, you don't even need this little block of code at all.
you first register your nib for the table view cell like so:
[self.tableView registerNib:[UINib nibWithNibName:#"nib name" bundle:nil] forCellReuseIdentifier:DefaultCellIdentifier];
in cellForRowAtIndexPath . you do not need to alloc the cell explicitly.
Instead you can do something like this
defaultCell = [self.listView dequeueReusableCellWithIdentifier:DefaultCellIdentifier];
[defaultCell configureCell];//In configure cell method set any images or labels u want.
return defaultCell
Hope this helps..
UPDATE 1 - correction in code
This is the correct way of showing a custom cell in your cellForRowAtIndexPath method
I learned something today:
you dont need to check if a cell was dequeued or not because the method will create a new cell from the nib if it can't dequeue one. - #Abizern,
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
//Set the label's data properties that you may have assuming you have a datasource.
cell.customLabelICreated.text = [myStringsDataSourceArray objectAtIndexPath:index.row];
Related
I am trying to create a project with a custom UITableViewCell. The custom cells never load, they're just blank. At this point in the project what I'm trying to do is placing a UITableViewCell in a .xib, designing it the way I want and specifying its reuse identifier along with tag IDs for the components so that I can use them in code later on.
I've googled a ton and found several tutorials that look like what I want to do, along with many SO questions that have answers that seem applicable. At this point it's probably just my head spinning with too many different angles and solutions.
This is my current attempt at trying to register the custom cell with my UITableView, yet when running this on a device the rows in the table view are entirely blank.
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
UILabel* l1 = (UILabel*)[cell viewWithTag:1];
UILabel* l2 = (UILabel*)[cell viewWithTag:2];
UILabel* l3 = (UILabel*)[cell viewWithTag:3];
l1.text = #"Foobar";
l2.text = #"Foobar";
l3.text = #"Foobar";
I'm pretty certain that I've hooked up all the properties and such correctly, but at this stage I need a fresh pair of eyes to point out the facepalm for me.
The interesting files are FilmerView.m/h/xib and the cell is in FilmerViewCell.xib. When running the app this TableView is in the second tab of the tab bar controller.
Project:
http://speedy.sh/WhhpP/test12.zip
I can't provide a full answer atm but look up the tableview method. registerNib:forCellReuseIdentifier:
Also, stop using that dequeue method. Use the one that includes the indexPath.
Then you don't have to check if the cell is nil afterwards.
EDIT
In viewDidLoad (or somewhere like that)...
UINib *cellNib = [UINib nibWithNibName:#"MyCustomCellXibFileName" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:cellNib forCellReuseIdentifier:#"CellIdentifier"];
Now in the table view datasource method...
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// no need to check cell == nil.
// this method is guaranteed to return a non nil cell.
// if it doesn't then the program will crash telling you that you need to...
// register a class or nib (but we just did this in viewDidLoad) :D
// configure your cell here...
[self configureMyCell:(MyCustomCell *)cell atIndexPath:indexPath];
return cell;
}
- (void)configureMyCell:(MyCustomCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.nameLabel.text = #"Hello, world";
}
Hope this helps.
Make sure that you have set datasource and delegate properties of your tableView.
Make sure that you have implemented (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method and it returns a positive value (>0).
Evaluate the following:
Is the ReuseIdentifier set in the XIB. See Properties Tab in Interface Builder on the right when selecting the cell.
Are the AutoresizingMasks set properly for the labels to be visible?
WrapModes: Which did you select? When having wrapmode WrapWord, is the font size too large for the text to be moved in the next line becoming invisible?
Set the background color of the UITableViewCellss content view to something else than white or transparent, as well as the background colors of the labels to see if the cell is even there.
Manually call numberOfRowsInSection on your table, pass the proper NSIndexPath identifying the target section and see if its greater 0 to confirm that the TableView even attempts to load the data, thus, the cells. ( Alternatively set a breakpoint in the method or do a NSLog. )
Do a NSLog in cellForRowAtIndexPath to confirm that the cell returned is not nil and the method is even called!
When I create a tableview with custom cell I use this
static NSString *CellIdentifier = #"mycell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
and it work fine (I work with storyboard and ARC)
but sometimes I see this control:
if (!cell){
//here the alloc of a custom cell
}
should I use this only when I have a custom cell with its class? If I use storyboard do I need it? thanks
dequeueReusableCellWithIdentifier:forIndexPath: will raise an exception if there is no cell to dequeue. So there is no point in checking if cell is nil. There is no way that cell will be nil after this call. You will either have a valid cell or an exception is raised.
That means you have to register a cell (through storyboard or in code) for this call to work.
There is a second (or old) way to dequeue cells, dequeueReusableCellWithIdentifier:, without the forIndexPath:. That's how we did it in earlier versions when there was no way to register cells. If no cell is registered for the identifier this method will return nil, and you have to create a cell in code.
I would stick with registering cells and dequeueReusableCellWithIdentifier:forIndexPath:. You don't need the if (!cell) part in this case. And the exception will make sure that you not forget to register your cells.
If you are using prototype cells with storyboard, you will never get inside that if statement, so you don't need it. Otherwise you do, for example when you instantiate the cell from a xib file, then you would do that inside the if statement.
If you are using storyboards use prototype cells. In this tutorial there is a whole section about protoype cells: http://www.raywenderlich.com/50308/storyboards-tutorial-in-ios-7-part-1
Its not necessary if we are using storyboard.Checkout this link
http://useyourloaf.com/blog/2012/06/07/prototype-table-cells-and-storyboards.html
I am using prototype cell to calculate real cell height. Since I'm using storyboard I have chosen to create prototype cell by dequeing it. Example code:
- (MyCell *)prototypePriceOptionCell
{
if (_prototypeCell == nil) {
_prototypeCell = (MyCell *)[self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
return _prototypePriceOptionCell;
}
This prototype is never returned to tableView in cellForRowAtIndexPath method.
Will it be dequed by table view to reuse and show it in table view?
You technically could, from the docs:
If you registered a class for the specified identifier and a new cell
must be created, this method initializes the cell by calling its
initWithStyle:reuseIdentifier: method. For nib-based cells, this
method loads the cell object from the provided nib file. If an
existing cell was available for reuse, this method calls the cell’s
prepareForReuse method instead.
But it also states that it can return nil under some circumstances.
However, I wouldn't use your approach, not because it wouldn't work but because it's not supposed to be used like that. This means that you have weak code relying on a feature it's not supposed to be used like that.
My suggestion, instantiate your cell manually calling the appropriate methods. Also, I like to have my cells on separate xibs, away from storyboards.
Edit:
Answering your question at the end, yes, the cell can and will be dequeued by the table view if you call dequeue in your cellForRowAtIndexPath
I have a problem settings my view elements on a custom cell. The table cells appear in my tableView, but the properties do not set and thus only empty/blank cells appear.
The tableView is not a tableView controller, but only a tableView in a viewController.
I have the following files:
CustomCell.xib:
Here i use IB to build the custom cell by using a Table View Cell from object library with labels and images on. I set the Identifier as orderListCell. From this screen I ctrl+drag to create the outlets in customCell.h
CustomCell.h
Here I see all my IBOutlets as properties from above mentioned file
CustomCell.m
Here I leave as is
OrderListViewController.h
Here I import customCell.h and use protocols UITableViewDelegate, UITableViewDataSource
OrderListViewController.m
Here I set my tableView delegate and tableView dataSource to self. I also create an IBOutlet for my tableView from the Storyboard.
I use the following code to try and display my cells:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"orderListCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[CustomCell alloc] init];
}
cell.myLabel.text = #"aaaaaaaa"; //[[self.orders objectAtIndex:indexPath.row] objectForKey: #"tableNo"];
return cell;
}
I have simplified my code a bit to demonstrate that even setting the label to a simple string (#"aaaaaaaa") doesnt work. When I look at the objects in my debugger the cell does have all the properties from the IBOutlets and the cell does appear in my tableView, just the label.text = xxx does not seem to work.
I have looked at the following posts but either dont understand it properly or it does not work for me:
ios 7 customizing UITableViewCell's content view
Can't set properties in Custom UITableViewCell
Set label for a custom cell
Any help or advice would be greatly appreciated
cell = [[CustomCell alloc] init]; does not create your cell from the XIB, so none of the XIB content will be created.
Use registerNib:forCellReuseIdentifier: to register the XIB with the table view so that it will create your cell instances for you (you don't need to create instances yourself in cellForRowAtIndexPath).
If you don't want to do that, you can load your NIB explicitly with nibWithNibName:bundle: and instantiateWithOwner:options:, then get the cell instance from the list of returned views (which should only contain 1 item).
I have a custom UICollectionViewCell that has a custom background view which is drawn using one of several colour schemes. The colour scheme for the background view is set in my custom initializer -(id)initWithFrame:andColourPalette: for the View.
I have a similar custom initialiser in my UICustomViewCell subclass but I can't figure out how to call this initialiser when I am setting up the cell in cellForItemAtIndexPath:
Can anyone help me do this? Or offer alternative solution for passing this Dictionary of colours into the Cell to pass on to the subView?
EDIT to show more detail:
This is what I have in my UICollectionView VC:
In ViewWillAppear:
[self.collectionView registerClass:[OPOLawCollectionViewCell class] forCellWithReuseIdentifier:CELL_ID];
self.colourPalette = [OPOColourPalette greenyColourPalette];
In cellForItemAtIndexPath:
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CELL_ID forIndexPath:indexPath];
OPOLawCollectionViewCell *lawCell = (OPOLawCollectionViewCell *)cell;
MainLevel *level = self.collectionData[indexPath.row];
lawCell.delegate = self;
lawCell.colourPalette = self.colourPalette;
In my Custom UICollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// get background view
OPOLawBook *lawBookView = [[OPOLawBook alloc]initWithFrame:CGRectMake(0, 0, 200, 265) andColourPalette:self.colourPalette];
But that doesn't work - I guess because the propertys are not set up.
If I change the last line to this, then it works fine:
OPOLawBook *lawBookView = [[OPOLawBook alloc]initWithFrame:CGRectMake(0, 0, 200, 265) andColourPalette:[OPOColorPalette greenyColorPalette]];
So i guess I need to use a custom intialiser here but I cant figure out how to call it , or from where...
Thanks
Yuo have to register your customCells in collectionView:
[self.collectionView_ registerClass:[YourCustomClass class]
forCellWithReuseIdentifier:#"CustomCell"];
And then in your method cellForItemAtIndexPath:
YourCustomClass *cell = (YourCustomClass *)[collectionView
dequeueReusableCellWithReuseIdentifier:#"CustomCell" forIndexPath:indexPath];
It is done because collectionView might have 1000 cells and 10 visible. You don't keep all of them initialized and reuse when possible.
EDIT
You should set colorPaletter after you deque the reusable cell. Think of it as a container which can hold any color. You need to determine (by indexpath) what color to paint.
You shouldn't do below if your custom cell is in the Storyboard,
[self.collectionView registerClass:[OPOLawCollectionViewCell class] forCellWithReuseIdentifier:CELL_ID];
Because Storyboard take responsibility to register Cell_ID own.
Now, It will conflict to be generated invalid Cell if you use both.
Way off, every answer. The questioner is looking for a way to uniquely identify each cell upon initialization, which happens prior to dequeuing a cell, and prior to a cell's access to its index path property.
The only way to do this is to assign a unique reuse identifier to every cell based on what the index path value will be (assuming you will know what that will be—and, in your case, you will); then, when dequeuing the cell, use the index path to find the cell with the corresponding reuse identifier.
Does this negates the purpose of reuse identifiers? Absolutely not. You'll be reusing that cell every time you need to use it again. Reuse identifiers were not meant to limit you to a cookie-cutter cell for every cell in your collection view; they are also intended to be "unique use" identifiers.