How to resume the CAAnimation group after cell reuse? - ios

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.

Related

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.

How to enable didSelectRow on selecting an element included inside the cell?

Well I have gone through web to search an easy implementation of this question but all I heard is coincide with what I thought at beginning which is not easy enough.
I was wondering if anybody could provide a better and easier implementation to solve this issue.
Well looking at the picture below, (Please neglect the crudeness of the picture)
I have a table view with multiple cells.
And based on the data, there will be different element(s) inside each cell.
If I touch inside the scrollview in cell 2 as shown in the picture. The delegate method for the tableView "didSelectRowAtIndexPath" will NOT be called, which is a problem for me.
So my first thinking is either to trigger the [tableView selectRowAtIndexPath] within the Scrollviews delegate method or I attach another tapGesture to these subviews and trigger it from there. But it already doesn't sound like a intuitive implementation and hard to maintain.
Anybody got any idea how could this be solved in an easier way?
Thanks
There are a wide variety of objectives you might be trying to accomplish here, so I won't speculate on the ultimate goal which you haven't told us, but in general:
If you would like two different UIElements to execute the same chunk of code, then you encapsulate that code in a stand-alone method, and call that method from both places.
In your UIScrollView as a subview of a UITableViewCell example, you would call it from within -(void)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath and you would also call it from the gesture recognizer that you attached to your scrollView.
I will speculate that the part you're having trouble with is knowing which scrollView was touched, or which row the scrollView was in. One possible approach would be to send the UIScrollView or the UITableViewCell as a parameter for the standalone method you created. -(void)doSomethingSpecialWith:(UITableViewCell*)cell or -(void)doSomethingSpecialWith:(UIScrollView)view
Post some more code, or feel free to explain your agenda further, but I have a strong feeling that the best way for you will be to subclass UITableViewCell, add the UIScrollView as a property of the custom cell, and wire up the gesture recognizer to call a method of your subclassed UITableViewCell.
i think the better way to solve this problem is :
creat custom method , - (void)tableviewSeletedIndexPath:(NSIndexPath *)indexPath
you can call this method in TableViews delegate -(void)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath , and call this method in your scrolls method.
Make the tag of scrollView is equal to the current cell row:
scrollView.tag = indexPath.row;
Make your ViewController to be the delegate of UIScrollView and in didScroll get the index and call didSelect:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSIndexPath *index = [NSIndexPath indexPathForRow:scrollView.tag inSection:0];
[self tableView:self.tableView didSelectRowAtIndexPath:index];
}

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

Knowing when a UITableView is done loading its cells

The purpose of this question is not to know when a UITableView is done loading its data (which has been answered in this post) but to know when a UITableView has done drawing all its cells.
Using the visibleCells property inside the
- (UITableViewCell *)tableView:(UITableView *)iTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method doesn't work because when the tableview is loaded for the first time, no cells are visible yet.
The idea is to animate the cell appearance when the tableview is refreshed.
This seems like a complex task to perform but I'm surprised Apple didn't provide any delegate method to use when a tableview is done loading.
Better try this method, pass NSArray of indexPaths that you want to reload with given set of animation
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Hope it works
I don't believe there is a method that indicates when a table has loaded it's cells. However, you can achieve your goal of animating in the table cell whenever it is drawn.
Logic:
UITableView displays UITableViewCells as needed.
Each UITableViewCell is a subclass of UIView.
UIView has drawRect, which is called every time the view is drawn.
So, put your animation in UITableViewCell's drawRect method & it'll animated whenever it's drawn.
Implementation:
Create a subclass of UITableViewCell,
Apply this subclass to your table cells,
Add the drawRect method, and
Implement your animation in the drawRect method.
I have done this in one of my projects and it worked great. It draws the animation when the table is loaded or scrolled and when the display is rotated. With this approach you don't need to know when the table is done loading – each cell is simply animated whenever it is drawn.
One final note – if you put another view controller on top of your table view and then dismiss it, you may need to reload the table and set each UITableViewCell to setNeedsDisplay. This will force drawRect to be called again for each UITableViewCell.

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

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.

Resources