I implement a UITableView of UIImageView cells, each of which periodically refreshes itself every 5 seconds via NSTimer. Each image is loaded from a server in the background thread, and from that background thread I also update the UI, displaying the new image, by calling performSelectorOnMainThread. So far so good.
The problem I noticed is the number of threads is increasing over time and UI becomes non-responsive. Therefore, I want to invalidate NSTimer if a cell goes off screen. Which delegation methods in UITableView should I use to do this efficiently?
The reason why I associate an NSTimer with each cell because I don’t want image transition to occur at the same time for all cells.
Is there any other methods to do this by the way? For example, is it possible to use just a single NSTimer?
(I can’t use SDWebImage because my requirement is to display a set of images in loop loaded from a server)
// In MyViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSTimer* timer=[NSTimer scheduledTimerWithTimeInterval:ANIMATION_SCHEDULED_AT_TIME_INTERVAL
target:self
selector:@selector(updateImageInBackground:)
userInfo:cell.imageView
repeats:YES];
...
}
- (void) updateImageInBackground:(NSTimer*)aTimer
{
[self performSelectorInBackground:@selector(updateImage:)
withObject:[aTimer userInfo]];
}
- (void) updateImage:(AnimatedImageView*)animatedImageView
{
@autoreleasepool {
[animatedImageView refresh];
}
}
// In AnimatedImageView.m
-(void)refresh
{
if(self.currentIndex>=self.urls.count)
self.currentIndex=0;
ASIHTTPRequest *request=[[ASIHTTPRequest alloc] initWithURL:[self.urls objectAtIndex:self.currentIndex]];
[request startSynchronous];
UIImage *image = [UIImage imageWithData:[request responseData]];
// How do I cancel this operation if I know that a user performs a scrolling action, therefore departing from this cell.
[self performSelectorOnMainThread:@selector(performTransition:)
withObject:image
waitUntilDone:YES];
}
-(void)performTransition:(UIImage*)anImage
{
[UIView transitionWithView:self duration:1.0 options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction) animations:^{
self.image=anImage;
currentIndex++;
} completion:^(BOOL finished) {
}];
}
If you properly manage memory and dequeue reusable cells, you can subclass
UITableViewCelland override its- prepareForReusemethod in order to stop the timer.Furthermore, as @lnfaziger points out, if you want to stop the timer immediately when the cell is removed from the table view, you can also override its
willMoveToSuperview:and/ordidMoveToSuperview:method and check if itssuperviewparameter isnil– if it is, the cell is being removed, so you can stop the timer.