iOS:如何阻止后台线程更新主线程中的UI? [英] iOS: How to stop a background thread from updating UI in the main thread?
问题描述
我实现了UIImageView单元格的UITableView,每个单元格都通过NSTimer每5秒定期刷新一次.每个图像都是从服务器在后台线程中加载的,从该后台线程中,我还通过调用performSelectorOnMainThread
来更新UI,显示新图像.到目前为止一切顺利.
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.
当我不等到在当前单元格中加载图像并且快速向下滚动到新单元格时,我会遇到一个问题.但是,该新单元格显示的是前一个单元格的图像,而不是新单元格的图像.尽管下一轮NSTimer将正确显示图像,但这起初可能会使用户感到困惑.
Currently I face a problem when I don't wait until an image is loaded at a current cell and I scroll down quickly to a new cell. That new cell, however, displays an image of a previous cell instead of the new cell's. Although the next round of NSTimer will correctly display the image, but this can confuse users at first.
如果我不重用UITableView的单元格,问题将消失,但是鉴于要在我的应用程序中显示的单元格数量,这不是一个选择.
The problem would be disappear if I don't reuse UITableView's cells, but given the number of cells to be displayed in my app, this is not an option.
因此,我能想到的唯一解决方案是,如果我知道用户执行了滚动操作,则取消(或杀死)将显示旧图像的后台线程.
So the only solution I can think of is to cancel (or kill) the background thread that is going to display an old image if I know that a user performs the scrolling action.
我想知道这可能不是最佳做法,因此请寻求您的建议.
I wonder that this might not be the best practice and, therefore, seek for your advices.
(我也不能使用SDWebImage,因为我的要求是循环显示从服务器加载的一组图像)
(I also 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) {
}];
}
推荐答案
好吧... 另一种方法是将图像请求代码"放入AnimatedImageView,并在每次设置新的图像URL时使待处理的请求无效
Ok... Another way to do that would be to put your 'image requesting code' INTO your AnimatedImageView, and invalidate pending request each time you set a new Image URL
// your controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
[cell.imageView setDistantImage:imageURL];
...
}
然后,在您的Cell类中,"setDistantImage"创建一个ASIHttpRequest,并使上一个无效.
Then, in your Cell class,'setDistantImage' creates an ASIHttpRequest, and invalidates the previous one
//your ImageView class
@property (...) ASIHttpRequest *distantImageRequest;
- (void) setDistantImageUrl:(NSUrl *)imageUrl
{
//clear previous request
[distantImageRequest clearDelegatesAndCancel];
//set a new request, with the callBack embedded directly in this ImageView class
...
}
//animation and callBacks methods in this ImageView class too...
这篇关于iOS:如何阻止后台线程更新主线程中的UI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!