I have a UITableView that I followed a tutorial on AppCoda, and formatted 2 strings to be displayed in the table that I declared in the ViewController.h. Because my app is parsing a downloaded JSON file, it take a second or two to fill the strings with the variables I want to display. My problem is that it only reloads when the cell reenter the view. What I need to do is reload the methods below when the parsing has finished.
Here are my ViewController.m methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_recipies count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
}
cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
cell.textLabel.text = [_recipies objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [_weatherArray objectAtIndex:indexPath.row];
NSLog(#"Updated");
return cell;
}
Calling [self.tableView reloadData] will reload your table view and call tableview: cellForRowAtIndexPath: as well. (If necessary replace self.tableView with whatever variable you're using to store a reference to your table view.)
Related
I'm trying to use "reloadData" method on a uitableView, it seems like it works (both dataSource method are being called) and when I debug "cellForRowAtIndexPath" the cell that it returns is the correct cell) but I can't see the cell (numberOfRowsInSection is changing and adding blank space for each new cell - So it's not seems to be a threads problem). For example, if I have in the tableView 5 "names" (my data array called "namesArray") and I add 2 there will be 5 names and 2 nil cells presented on the tableView. The problem seems to be with cellForRowAtIndexPath.
cellForRowAtIndex:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Creating "cellIdentifier"(NSString) with "Cell" as the value
NSString *cellIdentifier=#"Cell";
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[namesArray objectAtIndex:indexPath.row];
//Returning cell
return cell;
}
numberOfRowsInSection:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.namesArray.count;
}
-(void)addNameToNamesArray:(NSString*)name
{
[self.namesArray addObject:name];
NSLog(#"namesArray lastObject: %#",[self.namesArray lastObject]);
//NSLog print: The correct name (the one that was added)
[self.tableView reloadData];
}
screenshot for "5 names and 2 nil cells":
Do you have any idea what can it be?
You call
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
inside cellForRowAtIndexPath!
Don't you think that's a bit late? And if it worked, you would be calling it a bit often?
And if dequeue... returns nil when a class is registered, something is badly wrong.
change to
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Creating "cellIdentifier"(NSString) with "Cell" as the value
static NSString *cellIdentifier=#"Cell";
//[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[namesArray objectAtIndex:indexPath.row];
//Returning cell
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.namesArray.count;
}
set the outlet of tableview and then in addNameToNamesArray method after adding elements reload the tableview
This is likely because you have updated the data in your array, but the table view hasn't accessed that data yet, leading to the nil cells that you see. Since your cells load properly with the initial 5 element in your array, it's probable that you simply haven't refreshed the table view's data. Try using [tableView reloadData] after you have added the new elements to your array.
EDIT 1
What about changing your cellForRowAtIndexPath code to this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Creating "cellIdentifier"(NSString) with "Cell" as the value
NSString *cellIdentifier=#"Cell";
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textLabel.text = [self.namesArray objectAtIndex:indexPath.row];
NSLog(#"name: %#", cell.textLabel.text);
//Returning cell
return cell;
}
Let us know the output of NSLog.
1.Make sure you have initialized self.namesArray in viewDidLoad
Try the following:
[tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:cellIdentifier];
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];
}
cell.textLabel.text = [namesArray objectAtIndex:indexPath.row];
return cell;
}
Your code is perfectly alright. There can be some possibilities that its not working for you.
You are not initialising your datasource i.e NSMutableArray in your case.
It depends how you are calling addNameToNamesArray method.
If you can share your whole code for that class as how you are calling method and every delegates you are using.
I'm developing an iOS 7+ app, and I've some UITableViewController in storyboard that are showing a weird behavior. I've a basic prototype cell defined in one of them, with an identifier #"standardCell" also set in storyboard. In the associated UITableViewController class, I've this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"standardCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
Cells are loaded the first tiem the table view is shown, but as soon as I scroll the table content, all cell titles that were set appear empty and cellForRowAtIndexPath: is not called anymore. The didSelectRowAtIndexPath: delegate method is neither called.
I've set both delegate and dataSource for this table view to be the table view controller. And its .h file conforms to UITableViewController <UITableViewDataSource, UITableViewDelegate>.
I find a similar issue with another table view and associated view controller, where prototype cell is a custom cell instead: cells show wrong data and weird content when I scroll the table, as if cells where not being dequeued and reused as expected.
What could I being missing?
Thanks
at least in this method:
Change this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"standardCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
To this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"standardCell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
As soon as the table view gets touched the cell titles (and on-tap actions) disappear. I only use standard table view cells and store the values in an array. After the values disappear the table stays scrollable. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [[systeme objectAtIndex:indexPath.row] description];
cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell.textLabel setTextAlignment:NSTextAlignmentCenter];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"choseSystem" object:[systeme objectAtIndex:indexPath.row]];
}
You should be sure that the reuse identifier is the same for all cells if you use only one type of cells. You should do something similar to the following in the portion of your code where to retrieve a reusable cell:
NSString *CellIdentifier = [NSString stringWithFormat:#"CellReuseIdentifier", (long)indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
And make you you set the #"CellReuseIdentifier" in your xib file or your storyboard.
If you would like to use multiple custom cells for a table view you should do something similar to what you're doing, but take into account that reuse identifiers need to be configured for every type of cells.
Hope this helps!
The table view was fine. I just added its view as a subview to another view without keeping reference to the actual UITableViewController. That was the problem.
I have a simple tableView in which i change the cell whenever i click it in the function like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self shuftleCellExpansion:indexPath.row];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nil] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
Second Functions:
-(BOOL) shuftleCellExpansion:(int) indexP
{
if([opendedCells containsIndex:indexP])
{
[opendedCells removeIndex:indexP];
return YES;
}
else
{
[opendedCells addIndex:indexP];
return YES;
}
}
Cell for index Function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self isCellInExpandedList:indexPath.row])
{
NSLog(#"Cell is in Expanded State %hhd for Index Path %ld",[self isCellInExpandedList:indexPath.row], (long)indexPath.row);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"poCell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"poCell"];
cell.backgroundColor = [UIColor blueColor];
}
[[cell textLabel] setText:[searchResults objectAtIndex:indexPath.row]];
[cell imageView].image = [UIImage imageNamed:#"someicon.png"];
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"poCell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"poCell"];
cell.backgroundColor = [UIColor redColor];
}
[[cell textLabel] setText:[searchResults objectAtIndex:indexPath.row]];
return cell;
}
No the issue is that when ever i change a specific cell and then scroll it the cell at after the specific cells (i.e. after total visible cells) i see the same changed cell .
What is the efficient way to get Rid of this?
Every cell which go off the screen goes to reuse pool (mostly all data are erase) and if you scroll back the cell is populated in cellForRowAtIndexPath: method again.
You need to change the data source if you want to keep the changes.
In your didSelectRowAtIndexPath: you need to also make the changes in the array (I assume you use array to read the data from in cellForRowAtIndexPath:) you use in cellForRowAtIndexPath: to populate cell.
Hope this help.
// EXTENDED
To make it work you need to amend shuftleCellExpansion: method. In opendedCells you swap the indexes, I believe it reflect the changes in table view. In the same method you have to reflect the changes for searchResults array as well (swap the object as you did for opendedCells).
i have a uitableview with custom cells.. with normal code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
DDMainCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[DDMainCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}
the problem is when i select one cell i add progress bar on the cell that download data online.. but when i Scroll down i find that every 10 cells have the same progress bar .. how can i prevent this behavior ?
Try this,
- (void)viewDidLoad
{
[super viewDidLoad];
dataarr=[[NSMutableArray alloc]init];
indexarr=[[NSMutableArray alloc]init];
mytableview=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
mytableview.dataSource=self;
mytableview.delegate=self;
[self.view addSubview:mytableview];
for (int i=0; i<30; i++) {
[dataarr addObject:[NSString stringWithFormat:#"%d",i]];
}
// Do any additional setup after loading the view, typically from a nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [dataarr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text=[dataarr objectAtIndex:indexPath.row];
UIActivityIndicatorView *act=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[act setFrame:CGRectMake(50, 20, 20, 20)];
act.hidden=YES;
[cell.contentView addSubview:act];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[act startAnimating];
act.hidden=NO;
return cell;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[mytableview reloadData];
return;
}
[indexarr addObject:[dataarr objectAtIndex:indexPath.row]];
[mytableview reloadData];
}
Make sure, when downloading is complete, then remove this object from indexarr....
That's because your cells are getting reused; UITableView will put off-screen cells into the reusable cell queue, and dequeue them for reuse if the reuseIdentifier matches. You should use some other data structure (e.g. NSArray or NSDictionary) to track which indices/cells have already been tapped. Then, in the method you showed above, regardless of whether the cell was init-ed or dequeued, set the progress bar according to your underlying data structure.
Here your used UITableViewCellIdentifier is reuseIdentifier. Which will work for all Cells are same type. Now your are taking once cell with progress bar. Now it will different from all cells data.
So use one more tableview cell for progress bar, or while reloading table remove the Progress bar which is exists already and add again. for this use tag for progress bar.