Refreshing the view of UITableView - 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.

Related

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().

dequeueReusableCellWithIdentifier returns nil in didSelectRowAtIndexPath method

I'm using CustomTableCell in my project. I can see the "dequeueReusableCellWithIdentifier" is returning a valid cell in the method "cellForRowAtIndexPath" as it should eg whenever the table is reloaded.
In the CustomTableCell I have some images that I want to reuse, without downloading them again. However everytime i get a "nil" with the "dequeueReusableCellWithIdentifier" when used inside "didSelectRowAtIndexPath" delegate method.
The original table was not destroyed. The table is class object and I can see it is the same as the tableView received in the "didSelectRowAtIndexPath" parameter.
This behavior is consistent with out viewcontrollers in my project where I have used tableview.
I'm using ARC. Any idea what could be wrong ?
Thank you!
The question is a little vague, but I believe you're simply trying to access your custom cell from within "didSelectRowAtIndexPath". If this is the case, then you should utilize:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableCell *myCell = (CustomTableCell*)[tableView cellForRowAtIndexPath:indexPath];
}
Then you're free to access any part of your custom cell that you wish.
In case your curious:
"dequeueReusableCellWithIdentifier" is utilized to reduce the amount of object allocations & deallocations by reusing table cells that have "moved" beyond the visible range. i.e If you have a table with 1000 cells, but only 10 are visible at any given time. ~10 cells will be created and reused over and over again. Thus, when called dequeueReusableCellWithIdentifier will pull one of these cells off the stack of cells that aren't currently being utilized, or create one if the stack is empty.

How to make a UITableView row grow dynamically with the user modified content

I am asking this question already knowing the answer is "no you can't" but in the hopes someone has a brilliant idea here we go.
I have a subclass of UITableViewCell that has a few different subviews one of witch is a UITextField that I have as user editable. So naturally the textField grows with the text that is entered.
Now the question is how could I get the tableview row to grow with the textField.
I have a variety of different size cells so I know how to use - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath but the problem is that I need to modify the after the cell is already in the tableview.
Also note that the previously noted delegate method gets called before the data source delegate method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I have thought of just pulling up another view for the user to edit then putting that data into my data model then I would have to force the tableview to reload. (Can I reload just a certain cell/row)
Interestingly enough I think apple is doing what I want in their iTunes U app. When you tap a assignment it expands. I think they are using tableviews their right?
I know I have a lot of questions and talk here but I believe it is all related and just to show what I have researched. I am just looking for the possibility that one of you has a stroke of genius.
Hopefully this can help others also because this seems to be a hot topic but no one ask the question well or gets good answers.
Actually, this has been asked and answered many times -- it's not impossible. Search for "UITableView custom row height" or "UITableView multi line UITextField" or similar and you'll find several well-answered questions.
You're on the right track -- you need to return a height in tableView:heightForRowAtIndexPath:, even though that method is called before you create/configure the cell. This is okay... you just need a way to compute that height without having the cell. Other answers reference -[NSString sizeWithFont:constrainedToSize:] and related methods... this should get you on the right track.
Changing the height while the text field is editing is less obvious, but this answer has the key... if you call
[tableView beginUpdates];
[tableView endUpdates];
the table view will not only ask its delegate for heightForRowAtIndexPath: again and resize the cell to match, it'll do it with a smooth animation.

Adding data to a UITableView while the UITableView is visible?

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!

iOS - How to display the same table view after selecting an item

My iOS app is current transferring control to a detail view when an item in a UITableView is selected. This ia a quiz program, and I'd like to change the app so that it just redisplays the same table view with the correct answer highlighted when a row is selected. What's a good approach for doing this?
Is not clear to me if you know why the detail view is appearing. So I'll explain just in case. If you are giving control to a detail view is because somewhere in your code you are pushing that detail view. It depends on what kind of UITableViewCell you are using. If you are using one of the defaults styles, your detail view is probably been pushed in either:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
or
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
If you are using a custom cell, then you need to look for the method in charge of pushing
that detail view.
I think a good approach would be to:
Remove that pushing wherever it is.
Not to use an `UITableViewCellAccessoryType, if you are using one.
Do something similar to the following on your tableView:didSelectRowAtIndexPath:
Find the row for the right answer in your model array, according to tapped cell.
Use that row number to generate an NSIndexPath.
Use that NSIndexPath to find the correct cell with cellForRowAtIndexPath:
Call setSelected:animated: on that cell to highlight it.
NOTE: If your quiz has more answers than the amount of UITableViewCells that fit in the screen you should scroll your UITableView to the right answer for better UX.

Resources