when is this called : - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - ios

When is cellForRowAtIndexPath called when the cells of a TableViewController are added dynamicall? Is it after ViewDidLoad? We never trigger anything programatically to tell the app that we have done all the initial work we need to do and now you can start adding the cells with the corresponding details, discousure etc...
I am terribly confused and therefore I have no clue about the flow of execution of controls in a TableViewController. Please help me !

The delegate calls for the tableView will only be called if the table exists, for the table to exist the view must exist as it is part of the view. The viewDidLoad is called right after creating the view. So in short: viewDidLoad is called BEFORE tableView:cellForRowAtIndexPath:.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is a delegate method of a UITableView. It is called every time a cell is becoming visible(appearing on the screen due to scrolling for example).
And at the beginning it is called after viewDidLoad as many times as necessary(depending how many cells should be present).
Hope it helps

it is called after viewDidLoad, and yes it is called for every cell dynamically. you can put breakpoints and check the flow. hope it helps. happy coding :)

The tableview knows that when it's unarchived it needs to load its data.
As a general tip, if you want to know when a method is executed you can set a breakpoint. Xcode lets you choose whether to pause or continue when a breakpoint is met, so you can trigger a set of actions when different methods are encountered to find out what order thet occur in.

Related

How to resume the CAAnimation group after cell reuse?

I wrote some CAAnimation code in Cell. It's working proper at the first show of cell. but after the cell reuse. The animations is stop. Almost all the way on internet. It remove the animation and add again. But I hope I can get the animation and resume again. Anyone know how to that? Thanks for your help.
I also find apple give a way to stop and resume the CAAnimation. But It's seem don't work in my project only use the resume code.
Here is the line. QA1673
I use CAAnimationDelegate to watch the animation status. When the cell scrolled out of bounds, They call the - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag to tell the animation is stop. so apple stop it not by accident.
That's the all info I got.
As you have discovered, the cell's awakeFromNib is only called once for a cell, even though it potentially will be reused many times. I would suggest to put your code as follows:
In UITableViewCell or sub-class
- (void)awakeFromNib
Called once for the lifetime of the cell.
Place initialization code that is independent of the cell's content.
- (void)prepareForReuse
Called when the cell is about to be re-cycled.
Place cleanup code that must be called before reusing the cell here. Usually you do not need to use this, but can put the code in cellForRowAtIndexPath instead. See below.
In class implementing UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Called for every cell the table view wants to display.
Place initialization code that is dependent of the cell's content here. I suggest you put your animation code here.

Handle deselect row in table view

I want to handle case when user deselect row (that already selected) by tap on this row. It is well known that tableView:willDeselectRowAtIndexPath: / tableView:didDeselectRowAtIndexPath: delegate methods not called in this case: they are called only if you tap on other, unselected yet row (my table view have single selection mode).
tableView:didSelectRowAtIndexPath: method also not called when I am deselecting row.
Is there is any easy solutions?
Update
The problem was in tableView:willSelectRowAtIndexPath: method, where I return nil in some cases, thats why tableView:didSelectRowAtIndexPath: didn't call. Thanks #Nekto for useful information and helping.
Apple docs say next about - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
This method isn’t called when the editing property of the table is set to YES (that is, the table view is in editing mode).
That means that this method should be called unless your code has a bug or you haven't updated delegate of your table view or table is in editing mode.
One of the possible problems could be that you have incorrectly implemented - (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath and are returning nil for the selected row. In that case didSelect... isn't called:
Return nil if you don’t want the row deselected.
Alternatively you can implement another table view delegate method: - (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath:
Tells the delegate that the highlight was removed from the row at the specified index path.
See more about managing selections in table views here.
You can still use tableView:didSelectRowAtIndexPath, just use it like a check mark system would work.
The answer here explains how to use a checkmark. You can use this, or use the answer here.
I have such use case. Why you don't create a variable for lastSelectedRow(here I have problem if it was NSIndexPath and I used two integers) and on the method for selecting row just compare currentSelectedRow with lastSelectedRow.

Infinite Scroll on iOS with Swift

I'm an iOS newbie and I would like to know how to detect when the user scrolls and reaches the bottom of an UITableView so I can load new data into the table.
I would also like to know where such a method should be implemented (the tableview's class or the view controller in which this tableview exists)
Cheers!
You can use -(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath to and check if the last cell will be shown in the TableView's data source.
iOS' TableViewController takes care of that automatically. It asks its datasource only for the currently visible rows of the table (tableview.cellForRowAtIndexPath)
See the documentation for the UITableViewDatasource Protocol Reference
If you've got a "known dataset" (as in, you don't need to make a network call to fetch new data), then like #zizoft said, it'll be handled automatically in tableview.cellForRowAtIndexPath
If, however, you've got an "unknown dataset", (as in, you'll need to pull down data from the internet), you'll need to do something a bit more interesting - #ansible's suggestion would be appropriate in that case.

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.

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

Resources