I have the following method that should populate the cells of my UITableView with data from an array. I want to get the data from the array using the row that the data is being loaded into as the index.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cellComments=(FullCommentCell *)[tableView dequeueReusableCellWithIdentifier:FullCommentCell_ID];
if(cellComments==nil)
{
[[NSBundle mainBundle]loadNibNamed:#"FullCommentCell" owner:self options:nil];
NSLog([NSString stringWithFormat:#"%i",indexPath.row]);
[cellComments loadFullComments:[latestFMLComments objectAtIndex:indexPath.row]];
}
//cellComments.userInteractionEnabled=NO;
return cellComments;
}
This is not working as expected. The table only ends up being populated with the first three elements of my array and then this data is reused until my table ends. The table should be using all the data from my array. Any idea why this is not working as expected?
You need to set the correct cell data each time you return a cell, whether it's new or reused. As you scroll down, cells from the top of the table are removed and reused for the bottom of the table. That's why you're seeing the first few data items repeated.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cellComments = (FullCommentCell *)[tableView dequeueReusableCellWithIdentifier:FullCommentCell_ID];
if (cellComments == nil) {
[[NSBundle mainBundle]loadNibNamed:#"FullCommentCell" owner:self options:nil];
// Do any one-time setup here, like adding subviews
}
// Set cell data for both new and reused cells here
[cellComments loadFullComments:[latestFMLComments objectAtIndex:indexPath.row]];
//cellComments.userInteractionEnabled=NO;
return cellComments;
}
When you get the cellComments back from the dequeueReusableCellWithIdentifier call, you need to call loadFullCommnents again - cells are reused so you'll only have as many created as show up on screen.
Related
i've a UITableView and I'm reading a data from a web service.
the data from the web service may change at any time, so i have to refresh my data periodically.
i've managed to refresh the data and store it in an NSArray, but the UITableView won't display those data.
i tried
[myTableView reloadData];
but it have no effect.
EDIT:
i've implemented all the methods to load the data from an NSArray to the UiTableView.
this works when the NSArray is initialized in the ViewDidLoad.
but if the NSArray changed while the application is running, the UITableView Will not display those changes.
You need to implement the UITableViewDataSource delegate protocol, specifically - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Use this method to set up the cell. You can use the row property of indexPath to determine which cell you are setting up and provide it with data from your array.
For example
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
id item = [dataArray objectAtIndex:indexPath.row]; // Whatever data you're storing in your array
cell.textLabel.text = [item description]; // Substitute this for whatever you want to do with your cell.
}
EDIT:
reloadData should call
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
to see if there are any cells to be drawn. Make sure you implement these methods as well and return non-zero values or your table view won't try to draw any cells and - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath won't be called.
Parse
You may also be interested in this library which claims to make remote data-driven tables a lot simpler.
You have to call the function where you put the content into the table.
I feel like a real noob asking this, but here's my problem:
I want to show a tableView, with 7 custom cells. None of these cells is reused. That means the user will see 7 different cells, not more, not less.
I created the cells in the viewDidLoad method, and added all those cells in the listCells-array. After that, I used easy-mode to draw those cells:
UITableViewCell *cell = nil;
if (indexPath.row == 0)
{
static NSString *MyIdentifier = #"Cell";
cell = (DetAlertCell *)[localTableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"DetAlertCell" owner:self options:nil];
cell = [listCells objectAtIndex:indexPath.row];
}
}
....
However, this won't work. It shows me a blank view. Every cell is created using a .xib-file and a .h and .m class. Is there anything that I'm missing and should do?
Just don't call the [localTableView dequeueReusableCellWithIdentifier:nil] and loa the correct cell for the index path.
Also you say that you load the cells in the viewDidLoad, then why do you load the nib:
[[NSBundle mainBundle] loadNibNamed:#"DetAlertCell" owner:self options:nil];
They should already be the array should they not.
And why to you check if the row is 0 then load the row, still will only load the first row.
Try this:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [listCells objectAtIndex:indexPath.row];
}
I have a simple cell - designed in IB - and with the reuseIdentifier set. Below code works quite nicely. HOWever - the NSLog() reveals that the results are never cached.
Table view controller class:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch/case for various cell types
{
Foo * item = [results objectAtIndex:indexPath.row];
return [MyCell tableView:tableView populatedCellWith:item];
}
}
MyCell class..
+(UITableViewCell *)tableView:(UITableView *)tableView populatedCellWith:(Foo *)item
{
static NSString * identifier = #"XXX";
MyCell *cell = (MyCell *) [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
NSArray * items = [[NSBundle mainBundle] loadNibNamed:#"MyCell"
owner:self options:nil];
cell = [items objectAtIndex:0];
assert( cell && [cell.reuseIdentifier isEqualToString:identifier]);
NSLog(#"That was a load - rather than a nice cache for %#", self.class);
}
fill out some stuff.
return cell;
}
Why is this - as it makes things a lot more efficient ?
Thanks,
Dw.
The way you create the table view cell can not make sure to put the cell into the reusable queue in table view. Only way to do that is to use
initWithStyle:reuseIdentifier:
Initializes a table cell with a style and a reuse identifier and returns it to the caller.
My another question
Are you sure the cells have been set with a cell identifier? UITableView will not cache those without.
What I've done is created a custom TableCell view that gets populated with information from an array of objects. Each TableCell gets loaded in the
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"Cell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = (NSDictionary *)[self.surveys objectAtIndex:row];
cell.info1.text = [rowData objectForKey:#"info1"];
cell.info2.text = [rowData objectForKey:#"info2"];
cell.info3.text = [rowData objectForKey:#"info3"];
cell.otherInfo = [rowData objectForKey:#"otherInfo"];
return cell;
}
In addition to this I specify a custom height for the cell here
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 76.0;
}
When the value for tableView: heightForRowAtIndexPath: is 76 it loads all the cells that I can see and they aren't ever blank. Without changing anything else in the code I can modify the value in tableView: heightForRowAtIndexPath: and it will only show the first cell value when the view is loaded. As I scroll down they are refreshed with a value as soon as their top edge hits the top of the screen. When I get back up to the top and stretch the view so that it bounces back the bottom ones will disappear.
As far as I can tell, the change in height somehow affects how they are loaded but I can't for the life of me see how.
I specified a height in the custom cell .xib that was different than the one I was specifying in code. Once this was changed to match the size specified in the code the problem went away.
Another thing to pay attention to isn't just the size of the Custom table view cell's height but also the height of other sub views as well.
I had this problem when one of my UIImageView objects was higher than the cell height it would cause this very same problem.
Thanks for the post as it helped me sort out my issue too. +1 (wont let me vote up or I would, sorry)
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 :)