Adding data to a UITableView while the UITableView is visible? - ios

I've read every post here on SO regarding UITableView and reloadData, and nothing I've found has worked for me.
In the UI builder I have a UIViewController xib file with a UIView in it, and on that UIView, a UITableView. My UIViewController subclass is references as the File Owner for the xib. My subclass is a UITableViewDataSource and UITableViewDelegate, and I've wired up the dataSource and delegate referencing outlets to point to the UITableView in the UI builder. I've linked the UITableView in builder to the IBOutlet defined in my subclass.
Initially when the UITableView is displayed, the underlying NSMutableArray that I'm using as the data source has no data it, so the UITableView is empty as expected.
Later on, I modify the array, adding data to it.
I then have tried the following to refresh the view of the UITableView, all to no avail:
Called [myTableView reloadData] after changing my array
Called [myTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
Called insertRowsAtIndexPaths on the myTableView, thinking I might need to actually tell it which row to update.
None of these work. However, the data is there and everything seems to be wired up OK, as whenever I drag the UITableView up and release, so that the first row has temporarily disappeared, suddenly it does display the expected content when it comes back into view.
Any ideas?

I am sure that you right to call [tableView reloadData]
But you may want to set the [array count] in this method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
And within
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [array objectAtIndex:indexPath];}
This should allow you show the data from the array.

Although I had everything wired up correctly, I was chasing my tail. Ultimately the problem was not with the UITable at all, and not with the underlying array being used as the basis for my UITableView, but with the dictionary I was using to generate the text for each cell!
The array was being updated correctly, then reloadData was being called. But the dictionary wasn't being loaded with the necessary data until AFTER reloadData was being called. So the UITable was being "populated" with the right number of rows, but they all appeared blank, making it seem like things weren't working at all.
Once I took the trailer trash method of NSLogging some debugging data for each call to my UITableView delegates, it became obvious that things were being called as expected, but the data was not being pulled correctly for each cell.
Whew!

Related

No data at all is showing in UITableView

I have created numerous Xcode projects to see if this was a single project problem but no. The problem that I am getting is that when I populate a UITableVIiew with either local data or data that is stored in a Parse database it does not show.
I have tried re-installing Xcode, cleaning my project and walking through the code/project to see if I'd made a mistake but everything looks in place.
An example is that I created a UITableViewController with a UIImage in the cell and when I build and run the project it does not show up.
Here is an example:
Thanks in advance.
You should implement two required methods of UITableViewDataSource.
Something like that:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
return cell;
}
This would go quicker if you just posted the available code... Annnnyway...
The reason I ask is because if you've only done this in storyboard, and it's a dynamic table, the table looks to your numberOfRowsInSection method to see if it should be populating the table or not. If this is 0, then you'll get no rows no matter what you put into the storyboard.
Also, if you've got a cell identifier of cell in your cellForRowAtIndexPath, but you haven't identified your storyboard cell as cell, then you'll still get blank cells.
Furthermore, if you have implemented these two methods correctly, you need to ensure that this table is hooked up to that class as it's dataSource, either via storyboard or programatically.
But these are all just guesses because I would need to see code to figure it out.
If you are using a UITableViewController, have you changed the cells to static?
You said you don't have any custom code other than what Xcode provides. That is your problem.
You need to implement the UITableViewDataSource methods in order to install your data into your table view. Xcode does not do that. The code Xcode puts into your view controller tells the table view that there is no data. You need to report that there is at least 1 section, and at least 1 row in that section. You then need to write code for cellForRowAtIndexPath that installs data from your model into your cells.
Nikita lists 2 of the 3 methods that you must implement before you table view will do anything.

Refreshing the view of UITableView

I understand the concepts of cell re-usability for Xcode 5.0 table views. However, I have one very weird observation which I don't understand and wish anyone of you could enlighten me here. Thanks.
I have implemented a table view with a search bar utility (just on top of the table view). Under each custom cell (prototype cell), whenever a user clicks on it, it will be marked with a checkmark (UITableViewCellAccessoryCheckmark). The number of cells are more than 10.
Observation:
- Without using any search, marking and unmarking a cell is working as intended. Cells are updated instantly along with their checkmarks.
- When doing a search, from the results given, marking and unmarking a cell is also working as intended.
[Problem] Here comes the weird issue: when cancelling a search, an already marked cell (marked during search) does not refresh itself in the tableview unless scrolling up or down is performed!
And hence, I wrote [tableview reload] at the end of tableview:didSelectRowAtIndexPath: method. Obviously, it doesn't refresh the tableview for me. Without further changing any other code, merely modifying [tableview reload] to [self.tableview reload] under the same method works!
Why is the only addition of "self." able to make the table cells refreshed instantly? I have always thought the first argument, tableView, from the method (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath is as equal to self.tableview. Obviously, my interpretation in this case is wrong.
Thank you. I'm sorry for my lengthy post.
My guess is that this UISearchBar comes from a UISearchDisplayController. Is that correct?
If true, that is a common misconception, but an easy one to understand.
When filtering your UITableView entries and showing results, UISearchDisplayController actually overlays the view with its own tableView, UISearchResultsTableView.
Thus, this overlaid tableView also gets to call data source and delegate methods on your implementation, and this is when the tableView argument from tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath stops being equivalent to self.tableView.
This means that calling [tableView reloadData] during filtering actually asks UISearchResultsTableView to reload its contents, not self.tableView, a property of your viewController.

Updating a UITable inside didSelectRowAtIndexPath causes leak in iOS7, but not iOS6

I have a UITableView that I modify (delete one row and insert one row) when the user clicks on any of the rows. Memory deallocation works great in iOS6 and earlier, but iOS7 will not release the tableview. Here is the basics of my code. I have reduced the code hugely, but the issue is still there.
- (void)tableView:(UITableView *)intableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[intableView beginUpdates];
[intableView endUpdates];
}
The begin/end updates cause the memory to get held somewhere. It's the same if I insert or delete rows (along with the background data array) inside this function. I subclassed the UITableView and cells with just adding:
-(void)dealloc
{
NSLog(#"deallocated %#",[self class]);
}
So that I can see when they get deallocated. Are we not supposed to update the tableview on selection anymore? Is it in a different thread where something gets held? (I have tried dispatch_async into different threads)
I could post more code, but my current code looks just like what I posted and it is still holding on to the tableview somehow and not deallocating it.

UITableView reloadData does not seem to cause cellForRowAtIndexPath: to be called

I am currently writing an app, using storyboards, that contains two UITableViews within the same window.
When running the application, the first UITableView will populate with a number of "Registration Numbers".
When the user taps on a cell, then the second UITableView is supposed to populate with detail about the selected cell.
When tapping a number in the first table I have a method that drives the:
[mySecondTableView reloadData]
Which it does. I am under the impression that when invoking the reloadData command, it should then call both:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
The first fires, but the second won't.
I have both the data source and delegate wired to self.
I am not sure what I am missing.
Are both methods meant to fire?
When things like this happen to me, it's usually because I'm calling -reloadData outside of the main thread.
After reloadData, try this:
NSIndexSet * sections = [NSIndexSet indexSetWithIndex:0];
[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationNone];
I found if the data change is subtle, the table view seems to optimize away the need to refresh.
Pointed answers doesn't solve my table view problem. It was still calling
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
however cell drawing method wasn't fired:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
My problem was that(because of my mistake of course) table view height was 0. So as table displays only cells that are visible, it never tries to display a cell. When I changed height value drawing cell method started to fire again.
Botom line double check your table frame and ensure you have non-zero width and height values!
I just incurred this same issue. I used a performSelectorOnMainThread to call a method which then calls the reloadData. This was necessary since I was trying to update outside the main thread as suggested by hatfinch.
Make sure you call performSelectorOnMainThread with waitUntilDone:NO, otherwise you may still have the same issue
Found another cause of cellForRowAtIndexPath not being called.
If numberOfRowsInSection returns 0, cellForRowAtIndexPath won't be called.
This happened in my case because of an NSArray being de-allocated during a view controller change and its consequent count (since it was nil) returning 0.
After banging my head against a wall for days this solved my problem:
Set the All Exceptions breakpoint and see if you are getting an out of bounds exception in your datasource. Without setting the breakpoint there is no crash and the tableview will simply fail to reload.
Full answer here
I was debugging a similar issue for hours before I realized my .reloadData() call was being executed by a callback of a previous instance of the view controller.
So my breakpoint was hitting on the .reloadData() call of my old instance of that view controller, but the new instance that was actually shown wasn't reloading because it wasn't the one executing the callback that called .reloadData().

UITableView stop updating UI without crashing after adding data

I have a problem that is driving me crazy.
I have an UITableView that is always in editing mode (it has to be).
The user can add new rows to it.
The navigationItem.leftbarButton of the tableViewController pushes a new controller just to do it, let's call it "newRowsVC".
Before the push the tableViewController set itself as the delegate of the newRowsVC, the protocol has only a method:
-(void) aNewRowHasBeenCreated
{
[self.tableView reloadData];
}
I start adding rows and everything works fine, each now row is immediately displayed in the tableViewController until the last new row will force the tableView to scroll because there won't be anymore screen real estate for it. Here, I have no idea why, the tableView, only it, is as frozen, with no scrollbar and doesn't respond to input. The app continues to run without a crash and I can even dismiss the tableViewController by tapping the navigationItem.rightbarButtonItem.
I can keep creating new rows, they are added to the array, the number of row in the tableView data source is computed correctly. But the table is like dead.
If I dismiss the tableViewController and then I come back to it, I see that all the rows previously created, also the ones not shown as soon as they were created are there!
I really do not have idea of how I can fix this.
The first thing I tried was to force the scroll after the reload of the table but it didn't fix it.
-(void) aNewRowHasBeenCreated
{
[self.tableView reloadData];
[self.tableView setScrollEnabled:YES];
}
I also tried forcing the tableView to scroll to the last row but it didn't fix it.
-(void) aNewRowHasBeenCreated
{
[self.tableView reloadData];
[self.tableView setScrollEnabled: YES];
[self.tableView scrollToRowAtIndexPosition: [self.tableView indexPathsForVisibleRows]last object] atScrollPosition: UITableViewScrollPositionBottom animated:YES];
}
I check the number of rows each time the table is reloaded. No error, the number is perfect and the new rows data are correctly in the array, also the data for the cells not shown.
I thought it could be because the tableView is always in editing mode so I tried setting it to NO but nothing changes, id din't fix the problem.
Two notes:
1)the tableView has to be the delegate of each one of it's custom cells. They have an UITextField and an UIStepper, handled by the tableViewController. I already tried to not set the tableViewController as the delegate of its custom cells but nothing changes so the problem is not this.
2) self.tableView.bounces = NO but this has nothing to do with the scrolling issue, the scroll is enabled.
Update: After more tests I found that if I remove the dequeue of the reusable custom cell everything works fine, so the problem should be about the reuse.
static NSString *CellIdentifier=#"MyCell"
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
Nicola
After hours I got it. As pointed out by Amit the problem was hidden in cellForRowAtIndexPath... It was hard to catch because it didn't happened all the times and the first times I enabled/disabled the cell reusing everything seemed the same so I did not link the problem to it. I got back on it after I tried about all the other options I had been able to think about.
The problem was in the reuse of the cells and the fact that the custom cell has the tableView as its delegate to handle its textView and the stepper without exposing them.
I got rid of all the delagion stuff and exposed the textView and the stepper as public properties of the view. By doing this I was able to set the tableViewController directly to be the delegate of the cell.textView and to add directly a target/action for the stepper.
Everything works flawslessly now.
Thanks to everyone who tried to help me!
Nicola

Resources