UITableView with limited number of cells - ios

I have an UITableView with ±10 different UITableViewCells to display full information about an object (description cell, photos cell etc.). So when UITableView is loaded, I do not need UITableView cells to be reused. Wouldn't performance be better if I somehow store UITableViewCells and prevent cellForRowAtIndexPath from being called? If so, what is the way to achieve alike behaviour?

First of all, you can not prevent cellForRowAtIndexPath from being called if you are gonna use UITableView. It is a UITableViewDataSource function and it's not an optional one. Otherwise, you won't be able to populate your tableview.
What you can do is use switch case on indexpath.row in cellForRowAtIndexPath and return necessary cell.

You could try by increasing prototype cell in Storyboard. each cell assign new cell identifier and you need to keep array of identifier matching their index with storyboard.
Your cellForRowAtIndexpath will reduced to:
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:[cellIdArray objectAtIndex:indexPath.row] forIndexPath:indexPath];
return cell;
}
Note: cellForRowAtIndexpath method will always called. In above case you can put your data in storyboard itself.
Check similar case at https://www.appcoda.com/sidebar-menu-swift/

Related

UItableviewcell Reuse issue in ios

Hello guys i think almost everyone who is in ios development may come across the issue of reuse of the UITableCell by using following code line.
RZRestaurantListingCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
I have search lot about this but not getting any desire answer so please help me out in this case.
I have the same issue as most of iPhone developer having after reusing the cell.
I have the UIProgressView inside my cell and one button is there for downloading the video and i am showing the progress there in progress view how much is left.
So Now what i have problem is when i have more data and going out of the screen at that time i am press the download button on very first row of the UITableviewCell then i am scrolling down so the progress also shown in bottom random one cell so the UI changes in two cell rather then one.
You need to implement -prepareForReuse method in your custom cell class and set all cell properties to default value.
- (void)prepareForReuse
If a UITableViewCell object is reusable—that is, it has a reuse
identifier—this method is invoked just before the object is returned
from the UITableView method dequeueReusableCellWithIdentifier:. For
performance reasons, you should only reset attributes of the cell that
are not related to content, for example, alpha, editing, and selection
state. The table view's delegate in tableView:cellForRowAtIndexPath:
should always reset all content when reusing a cell. If the cell
object does not have an associated reuse identifier, this method is
not called. If you override this method, you must be sure to invoke
the superclass implementation.
Refer here for more, https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/#//apple_ref/occ/instm/UITableViewCell/prepareForReuse
You need to assign a progress value inside the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RZRestaurantListingCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// If the cell is reused, the `-prepareForReuse:` of `UITableViewCell` will be called.
//!! Assign current progress value to this cell, otherwise, the progressBar.value may look like a random value.
//!! Because the current cell is reused from a disappeared cell.
cell.progressBar.value = ... ;
return cell;
}
The design may be complex, because the progress may be updated continuously when the cell is on the screen.
Use prepareforreuse method to clear content of cell before using it... e.g.
-(void)prepareForReuse
{
[super prepareForReuse];
self.textLabel.text = #"";
self.detailTextLabel.text = #"";
self.imageView.image = nil;
}

How to get reference to current UITableViewCell

At my experiment I need to have reference to first UITableViewCell in tableView. By some action I need to set image and some other cell properties and to keep this state of this only cell even if the tableView will be scrolled. All of this properties can be potentially nulled via scrolling (and they actually are) because of reusing. For set this properties every time cell appears on screen, inside of `-cellForRowAtIndexpath' I tried to catch first cell using:
UITableViewCell *firstCell = (UITableViewCell *)[atableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
but looks like this way I can only catch every next first cell on next scrollable "screen".
So, how can I get ref to first UITableView cell?
If I understand you correctly, you are trying to do something special if the cell at (0, 0) is about to be displayed, right? If that's the case, you can easily implement UITableViewDelegate's tableView:willDisplayCell:forRowAtIndexPath: method as follows:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath) {
// Do something special
}
}
There is also a corresponding tableView:didEndDisplayingCell:forRowAtIndexPath: method if you need to undo things.
Hope it helps!
There is no "first" table view cell. The entire table view typically uses a single cell to improve performance.
You can change that, by implementing your own cell reuse system (search for reuse in the documentation). But generally the cell is the wrong place to store any data related to a specific index in the table view.

how to identify a view object without assigning its tag property

I place textview in the prototype cells by storyboard and assign the textview's tag.
In the implantation method of
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:,
I wanna assign the textview another identifier so that I can obtain the textview by this identifier. The reason why I don't use the TAG property to do this is because that all the cells in my table view has the same prototype for reusing.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
ETPost *post = postList[indexPath.row];
UITextView *textView = (UITextView*)[cell viewWithTag:TEXT_TAG];//TEXT_TAG 1000
textView.text =post.content;
return cell;
}
as you can see above, I use the viewWithTag, all the cells in my tableview have the same tag, so I have to another solution instead of assigning the indexPath to the TAG.
Alright, the answer is probably simpler than you think. But just subclass UITableViewCell and make sure that your table view is using your new subclass (you set this up in the prototype cell Custom Class in IB and StoryBoards). The only thing the subclass adds is a property that allows you to identify it.
#property short specialIdentifier;
Here's a more general link on UITableViewCells which I generally refer to when I need something done: cusomizing uitableviewcells
in -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath: you could assign the indexPath's row number to your textView's tag like:
cell.textView.tag = indexPath.row;
so this tag would correspond with your cell's indexPath distinct assuming you place all cells in ONE section.

How to alter tableview cell text?

I have a UITableView that I want to alter some of the static cells after I do other processing. I have outlets set up for the cells that I want to modify, but when I look at them using NSLog, they show nil, which indicates to me that I don't have the correct cell. For instance, in the image below I want to add the start time to the label just like I did for Date (date was done when creating the cells for which I got the current date),
I tap on the disclosure indicator which takes me to another scene (this was created in Storyboard, using segues to get from one scene to another) where I get the two times I need. I then return to the main scene (shown) and try to alter the Start Time label, but nothing happens. A NSLog of the label prior to trying to alter it returns this:
oStartTimeCell.textLabel.text: (null)
I have read in one of the Apple docs that this textfield is read-only. If that is true in this case, is there a way I can reload the cells with the updated information? Or is there another way to do this?
You're using the wrong approach. You should not create a reference to a cell using an outlet. Once the cell moves out of the visible view, the outlet will either be null or contain garbage data. Even if (in your situation) the cell will never move out of view, I think it shows you're trying to use a UITableView in a way that was not meant to be.
Instead put the data you want to display in your cells in a dataSource, e.g. an array.
The tableView should use the dataSource to configure the values displayed in the textLabels of the cells. Once you want to update the text displayed in the cells, change the values in the dataSource and call reloadData on the tableView to force the tableView to call -tableView:cellForRowAtIndexPath: and related UITableViewDataSource methods.
Try to create an IBOutlet for each cell and connect it:
IBOutlet UITableViewCell *cell1;
IBOutlet UITableViewCell *cell2;
IBOutlet UITableViewCell *cell3;
And also change your method to:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(indexPath.row == 0) return cell1;
if(indexPath.row == 1) return cell2;
if(indexPath.row == 2) return cell3;
if (cell == nil) {
//create cell;
}
return cell;
}
Are you using a UILabel to display the text ? . If you are just create an outlet to the UIlabel and update it any method like cellForRwoAtIndexPath or didSelectRowAtIndexPath etc that is called after you tableView is loaded.
If you are not using a UILabel and just using cell.textLabel you could do something like
cell.textLabel.text = #"ChangedText" in cellForRowAtIndexPathMethod. Make sure you are editing the required cell by checking indexPath.row
Do [tableView reloadData] to call cellForRowAtIndexPath.

UITableView cells not nil at initialization

I am setting up my UITableView using storyboard editor. For creating my cells I am using the standard delegate method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell"];
if (cell == nil)
{
// Do cell setup
}
// etc
return cell;
}
Except when the cell is dequeued the very first time it's not nil, as it should be. So the code inside the if statement is never executed.
People get this error when their reuse identifiers are inconsistent, so I went ahead and verified that I am using the exact same reuse identifier in my storyboard views as I do in my code. Still facing the issue. I also have several tableviews within the project and each one has a unique reuse identifier. Still no dice. Anyone know anything else that could be wrong here?
That's not how UITableView works anymore. Reading your question, I think you might be confused about how it worked before as well. If not, sorry, the first part of this is just review. :)
Without storyboard cell prototypes
Here's how it used to work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// If the tableview has an offscreen, unused cell of the right identifier
// it will return it.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell"];
if (cell == nil)
{
// Initial creation, nothing row specific.
}
// Per row setup here.
return cell;
}
Here when you create the cell using the reuse identifier, you do only the initial setup here. Nothing specific to this particular row/indexPath.
Where I've put the Per row setup comment you have a cell of the right identifier. It may be a fresh cell, or a recycled cell. You're responsible for all setup related to this particular row/indexPath.
Example: if you set the text in some rows (likely) you need to set or clear it in all rows, or text from rows you set will leak through to cells you don't.
With storyboard prototypes
With storyboards, though, the storyboard and table view handle the initial cell creation! This is brilliant stuff. You map out your cell prototypes directly in the tableview when using storyboards, and Cocoa Touch will do the initial creation for you.
Instead, you get this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell"];
// You'll always have a cell now!
// Per row setup here.
return cell;
}
You're responsible for all the same per row setup as before, but you shouldn't need to write code to build your initial empty cell, either inline or in its own subclass.
As Ian notes below, you can still use the old approach. Just make sure not to include a cell prototype in the storyboard for the identifier you specify. The view controller won't be able to build your cell from the cell prototype, dequeueReusableCellWithIdentifier will return nil, and you'll be exactly where you were before.

Resources