I have a UITableView with custom cells. Most of the cells get drawn correctly. But some cells render for a short period (milliseconds) then the content inside the cell disappear.
For my cellForRowAtIndexPath, I have created a unique identifier for each cell for reuse. This is the identifier I use:
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
This way I guarantee that using cellForRowAtIndexPath will return the correct cell after scrolling because the UITableView is reusing the correct cell.
My question is: What could cause a cell to render for a short time then disappear?
Could it be a dimensions issue (some cells exceed designated space)?
Thanks for any information that could help resolve this problem.
EDIT (code for cell for row) :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell){
[tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.label.text=#"TEST":
}
return cell;
}
Related
Cell width always return 320, once reload the table then it returns proper cell width based on device(iphone/ipad).Below is the code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = #"testCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil)
{
cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier];
}
cell.textLabel.text = #"test";
return cell;
}
probably it's because in first time your cell will be created via
[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier];
but after reload table your cell will be reused via
[tableView dequeueReusableCellWithIdentifier:reuseIdentifier]
with "old" sizes.
To avoid this, use correct cell identifier in Interface builder, in this case you can even remove creating cell code
[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier]
cell will be always generated from interface
I have this little doubt about reusing UITableViewCell.
When we create UITableViewCell it kinda looks like following.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
[self configureCell:cell forIndexPath:indexPath];
}
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
So in my case, every cell in UITableView is different. And if UITableView reuses the cell the cell content is completely different.
Is it good practice to just pass CellIdentifier as nil so every time new cell is created instead given the condition that all cells are different ?
Or should I just move [self configureCell:cell forIndexPath:indexPath]; out and handle it on by my own ?
Cell reusability has its sense if you are using cell contents(same subviews) multiple time. Like you have two lables in your tableViewcell for all rows in your tableView. If you have small number of different cells. like if you have three types of cells to use multiple times in your tableView, you can use cell reusability with 3 different cell identifier.
But if you have all different cell, then its fine if you skip cell reusability.
The proper way of using reusability of the tableView is shown below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"FollowerCell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
The basic idea of reusability is that every time the similar type of cell should not be created, instead they should be reused just by updating their content.
What happens behind the scene is that there is a queue created in which these similar cells are added. Now Suppose there are 200 rows with different data but only 10 rows are visible. That in the queue only approx 14 cells will be present. Now as you will scroll the tableview up or down, this condition
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
checks wether the queue contains any cell, if yes a cell is fetched from the queue. Also the cells, which were earlier visible now on disappearing are added into the queue. This way everytime instead of new cells are created, the already created cells are used.
Now if you forcely make the cell = nil, than every time new cells will be created and added in the queue. Now if there are 200 data than queue will be containing 200 cells thus resulting in increase in memory size.
Hope it will help you in understanding the tableView. Happy Coding :)
I am afraid you have to move the configure cell code out of if condition to make every cell has its own content.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
[self configureCell:cell forIndexPath:indexPath];
}
While we saying reuse of UITableViewCells, we mean that we don't have to create the UIView hierarchy inside the cell every time. But you need to configure the content for different cells. Like cell.titleLabel.text = xxxx.
Meanwhile, you can use multiple reuseIdentifiers for different kind of cells. Or if you only have one such cell, you can define a cell as an attribute instance so that you don't have to create it everytime.
I've created a UITableView in my application. I've Created a custom UITableViewCell called VideoCell which contains a UIWebview, a UIImageView and a UILabel.
The UIWebView is the same size as the UIImageView and in the same location, but behind the UIImageView. I want to hide the UILabel and the UIIMageView when I tap the cell, so that the UIWebView is revealed.
The VideoCell has a ReuseIdentifier set in the storyboard editor which I use for dequeing the VideoCell from in tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"VideoCell";
VideoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
...
return cell;
}
How can I get a reference to the actual cell that I tap in tableView:didSelectRowAtIndexPath: in order to visibly change the properties?
I've tried just dequing with the same arguments
VideoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Which returns me a VideoCell, but with no fields set up
I've also tried calling tableView:cellForRowAtIndexPath:
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
but that returns me a new instance of the VideoCell with the correct fields set up, and this is not the one that is currently displayed.
VideoCell *cell = (VideoCell*)[tableView cellForRowAtIndexPath:indexPath];
Don't call the data source method present in ViewController, call the method on actual instance of your UITableView
Try using this
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
instead of
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
cellForRowAtIndexPath:
is the correct way to get the instance of the cell. If you are unable to retrieve the exact cell you want in this way, it just means that your implementation in that method is wrong.
I simply don't understand how to fix this from what's out there.
It's fairly simple, I add a UITextField to my UITableViewCell. The user may type in it, then after scrolling it out and back into view the contents will be reset back to its default status.
This is to do with re-using old cells with dequeueReusableCellWithIdentifier right? I just don't understand how to fix it!
Here is my code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Stop repeating cell contents
else for (UIView *view in cell.contentView.subviews) [view removeFromSuperview];
//Add cell subviews here...
}
You don't have to remove the cell contents once it is initialized they are never recreated, they are reused so your code should look like below
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}
And I assume you want to have some controls onto your cell, in this case you can try using CustomCell which creates all the subviews on initializations.
Usually, all your initializations should be in
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
//ALL INITS
}
and outside it you should update the values you added into the cell..
You need to set the inputted text back to the textfield, currently with reuse of cells, the textfield clears out the contents. You could try to store the textfield input in an nsstring property and in your cellforrow method, set the textfield text as that string, if the string has a valid value. That way, even on scrolling, the textfield will only display the user input that was stored into the nsstring property from the textfield.
Before You follow my Answer i want to tell you that following code is bad for memory management because it will create new cell for each rows of UITableView, so be careful for it.
But it is better to use, When UITableView Have Limited rows (about 50-100 may be ) then following code is helpful in your case. Use it, if it is suitable for you.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"S%1dR%1d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
/// Put your code here.
}
/// Put your code here.
return cell;
}
If you have limited rows then this is best code for you.
I am trying to add/remove cells to my grouped table dynamically during runtime. This is my first app that I have ever made, and while I have tried many other people's suggestions, I am still not getting it to work. Here is my code that I am using:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *lblName = (UILabel *)[cell viewWithTag:100];
[lblName setText:[intervalArray objectAtIndex:[indexPath row]]];
return cell;
You will need to update the array (will need to be an NSMutableArray) that is being used as the datasource for the UITableView. Then you can
[self.myTableView reloadData];
To reload the tableview
This is a good guide for dealing with updating TableView rows:
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/tableview_iphone/ManageInsertDeleteRow/ManageInsertDeleteRow.html