If we return 100 in numberOfRowsInSection like
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 100;
}
then how many cells will be created at a time in cellForRowAtIndexPath method?
If you are asking how many times the -tableView:cellForRowAtIndexPath: method would be called, the answer is it would be called as much cells are visible for the moment. When you scroll, it would be called for each new cell which is about to be displayed. How does it knows how many cells are visible right now? The -tableView:heightForRowAtIndexPath: is called for each cell to calculate the contentSize of the table view.
Actually it wont allocate all the 100 cells. Instead only those which will be visible at the moment. As we are using [tableView dequeueReusableCellWithIdentifier:cellIdentifier];, the cells are reused for memory handling.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
just returns the total number of cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
this method will be called each time you scroll a table view.
It depends on your cell type. If you set dequeueReusableCellWithIdentifier, then it initializes only what you see on the screen and when you are scrolling it will scroll down to the amount of rows you set in the method above.
It will allocate all 100 Cells but visible at a time only the Cells which will be fixed as per
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
height of the Cell and width of the UITableView Frame
The number of cell return its base on UITableView height. means it return number of cell display at first time. tableView:cellForRowAtIndexPath method call for only visible cell it is not call for invisible cell of UITableView. if you scroll then tableView:cellForRowAtIndexPath reuse previous invisible cell rather then cerate new one.
Agree with #pbibergal, if you are used dequeueReusableCellWithIdentifier and put a condition like below then at a time approximately nine(9) cell created at a time (number of cell is depend on tableview height). otherwise 100 cell created by system at a time.
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[MainCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if you used above code then at a time limited cell created at a time (nine cell) other wise 100 cell created at a time and it was affected in memory.
Related
In my iPhone application I have four types of cells. Every cell has it's own height. I'd like to set the height of the row for each table view cell but it crashes in this method:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(#"%#", cell);
if([cell.reuseIdentifier isEqualToString:PastEventWICellIdentifier]){
return 56;
}
if([cell.reuseIdentifier isEqualToString:PastEventWOICellIdentifier]){
return 56;
}
if([cell.reuseIdentifier isEqualToString:EventWICellIdentifier]){
return 112;
}
if([cell.reuseIdentifier isEqualToString:EventWOICellIdentifier]){
return 112;
}
return 56;
}
How can I resolve this?
You cannot get the cells using cellForRowAtIndexPath inside the method heightForRowAtIndexPath, because the cells are not there yet. They will be created after their heights are set.
You may set the heights of the cells based on their location using indexPath.row.
You cannot use method cellForRowAtIndexPath, this method is called before cellForRowAtIndexPath so the cells don't exists. You should have a list of Height already calculated when heightForRowAtIndexPath is called. Remember to not load all list in tableview because this method (heightForRowAtIndexPath) takes longer to load tableview...
I have created two types of prototype cells in storyboard. The dimension of one of them have been customized to accomodate UIButton object. However when the cells are created, they have the standard height. I can see the UIButton object but it gets truncated because of the cell height.
Why are the newly created cells different from the prototype cells?
The relevant section of the code is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if(cell == nil)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"PictureSelectionCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
pictureButtonProperty = (UIButton *) [cell viewWithTag:1];
}
}
Going forward, what are my options for creating the cell of the width (or dimensions) defined in the storyboard? Programmatically, I will be able to achieve this by creating a CGRect object with the specified dimensions and then create a cell using initWithFrame. However, I would like to avoid doing things manually.
Thanks for your response.
first of all you can always set it with code
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return YOUR_ROW_HEIGHT;
}
other way if you choose your UITableView if the storyboard, under the size inspector change the Row Height.
I have a UILabel in a custom UITableViewCell that gets resized when the device is rotated. The text in this label needs to be recalculated after the rotation because I am cutting it down to size and appending some text at the end.
E.g. the datamodel has: "This is a run-on sentence that needs to stop."
In portrait mode it becomes "This is a run-on sent... more"
In landscape mode it becomes "This is a run-on sentence that... more"
From (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
I am able to access the visible UITableViewCells and update the descriptions.
The problem seems to be that there are UITableViewCells that are cached but I can't get to. When I scroll the UITableView after a rotation, one or two cells that are below the visible area after the rotation don't have the correct text in the label. So they haven't been rendered via (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - but they weren't returned by [tableView visibleCells] (or via looping through all views returned via [tableView subViews]).
I've tried to access the "extra" cells via this method:
for (int index=max + 1; index < max + 3 && index < [cellTypes count]; index++) {
NSIndexPath *updatedPath = [NSIndexPath indexPathForRow:index inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:updatedPath];
if (cell == nil) { continue; }
[self updateCellForRotate:cell forRow:index];
}
(where max is the biggest row returned from visibleCells) but cell is always nil.
Is there anyway to flush the cache of UITableViewCells so that they don't get re-used? Or to access them so I can update them?
Thanks!
Two things.
First. In your didRotateFromInterfaceOrientation method you can simply reload the visible rows like so:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation
{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
NSLog(#"didRotateFromInterfaceOrientation:%d",fromInterfaceOrientation);
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}
Then I would recommend you add either the interfaceOrientation number or simply the table width to the dequeue cell name that way the tableView knows that cells in one rotation are different from those in another. Like so:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath withType:(NSString *)s_type
{
UITableViewCell *cell = nil;
// add width of table to the name so that rotations will change the cell dequeue names
s_cell = [s_cell stringByAppendingString:[NSString stringWithFormat:#"%#%d",#"Width",(int)tv.bounds.size.width]];
NSLog(#"%#",s_cell);
cell = [tv dequeueReusableCellWithIdentifier:s_cell];
if( cell == nil ) {
cell = [[[UITableViewCell alloc];
initWithFrame:CGRectZero reuseIdentifier:s_cell] autorelease];
}
}
Firstly, to reload all of your table cells use [self.tableView reloadData]
Secondly, add the line of code that is responsible for the shrinking inside the (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method.
Example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Some identifier and recycling stuff
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
//Make labels smaller
}
else {
//Make them bigger
}
}
Or you can just call your updateCellForRotate:forRow: method when making them. But I'm not sure how that function works, so I can't be too specific.
When you create the cell in cellForRowAtIndexPath:, add it to an array. Then, loop through the array, updating the text as necessary.
Hope this helps,
jrtc27
EDIT:
You say they are custom cells - could you not update your text in your UITableViewCell subclass?
So, I was having (what I think was) a very similar problem recently, and none of the posted answers helped me, I'm sorry to say.
My issue was that I deliberately resized and repositioned the UITableView upon rotation, and I did that programatically. The table cells in portrait took up the width of the view, and in Landscape were made somewhat higher but less wide. I then repositioned the elements of the cell depending on the orientation we'd come to.
Upon application start, the first viewing of the table was fine. Then I rotated and found that I appeared to have two instances of some elements, and these appeared to be where the cells had been visible in the first table. Rotating back then corrupted the initial orientation table with elements from the previous table.
I tried all of the applicable answers above, until I looked closer at the cellForRowAtIndexPath code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
I understand cell re-use is a great idea and all, but I really didn't need to retain (as in preserve) any cells and wanted them all bright, spangly and new after each rotation.
EDIT: In my own app I'll have maybe 20-30 rows maximum, as I personally don't like hugely long tables. If there were going to be lots of rows returned for a particular query I'd have some filters available to the user to help them sort out which rows they wanted. If you're going to have loads of rows displayed, then dequeuing them may cause you a performance impact that you don't want.
All I did was comment out the if and the following bracket, and my table cells renewed exactly as I wanted them to:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}
Apologies for the waffle, and the late answer to an old question.
Ben.
Waffles and cream, or syrup.
You can use this simple line on the shouldAutorotateToInterfaceOrientation method :
self.view.autoresizesSubviews = YES;
For me it works always successfully
I am facing a very strange problem with editingStyleForRowAtIndexPath method. I am planing to change the appearance of editable cells. It was working fine, but when i scroll the table i am not getting the table cell pointer in the editingStyleForRowAtIndexPath delegate method. So the new cells does not get the custom appearance.
I am using this -
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
// get tablviewcell pointer
UITableViewCell* pCell = [tableView cellForRowAtIndexPath:indexPath]; // <- not getting the pointer when scrolling the table and new cells come up
//Changin cell appearance here ...
}
Thanks in advance!
I think the table view may call this method before it assigns a cell to the given index path. A more reliable way to customize table view cells would be to override -tableView:willDisplayCell:forRowAtIndexPath:. You can test the cell's editingStyle property there and act accordingly.
The following method loads data from an array into custom cells of UITableView. The data is loaded in correctly. However, when I scroll down data in the above cells (the cells not visible) are changed to seemingly random elements in the array.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cellComments=nil;
cellComments=(FullCommentCell *)[tableView dequeueReusableCellWithIdentifier:FullCommentCell_ID];
if(cellComments==nil)
{
[[NSBundle mainBundle]loadNibNamed:#"FullCommentCell" owner:self options:nil];
}
NSString *row = [NSString stringWithFormat:#"#%i",indexPath.row+1];
[cellComments loadFullComments:[latestFMLComments objectAtIndex:(indexPath.row+1)] withCommentNumber:row];
//cellComments.userInteractionEnabled=NO;
return cellComments;
}
I also have the following method that handles when i click on a cell. When the data of a cell changes to some random element in the array - if i click on the cell (which calls the method below) the data in the cell is changed to the right data.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self tableView:tableView cellForRowAtIndexPath:indexPath];
}
Any ideas why this is happening??
You are using cached cells, the odds are that you are not resetting the subvview elements of your cell correctly in loadFullComments.
Elfred has the right idea. When using the
cellComments=(FullCommentCell *)[tableView dequeueReusableCellWithIdentifier:FullCommentCell_ID];
Method call, you need to ensure that any subviews/properties such as labels, images, text, etc. are set every time on that cell. You can't assume that you'll be getting a "fresh" cell with no contents.
For example, when displaying the cell at index 17, the table view might dequeue the reusable cell previously at index 3. This cell will have the same properties as it did when it was in index 3, and it is your responsibility to reset them. (Eg. Changing the text from "I'm Cell 3" to "I'm Cell 17".)
I changed the UITextView to a multi-line UILabel and the everything works now. I am not sure why this makes a difference - but hey it works :)