我實現了UIImageView單元的UITableView,每個單元通過NSTimer每隔5秒定期刷新一次。每個圖像在後臺線程中從服務器加載,並且從後臺線程中,我還通過調用performSelectorOnMainThread
來更新UI,顯示新圖像。到現在爲止還挺好。iOS:如何在主線程中更新UI的後臺線程?
當我不等到一個圖像加載到當前單元格並且我快速向下滾動到一個新的單元格時,我目前遇到了一個問題。然而,這個新單元顯示的是前一個單元的圖像,而不是新單元的圖像。雖然下一輪的NSTimer會正確顯示圖像,但這可能會首先讓用戶感到困惑。
如果我不重用UITableView的單元格,問題就會消失,但如果在我的應用程序中顯示單元格的數量,這不是一個選項。
所以我能想到的唯一解決方案是取消(或殺死)後臺線程,如果我知道用戶執行滾動操作,將顯示舊圖像。
我想知道這可能不是最佳實踐,因此,尋求您的建議。
// 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) {
}];
}
WWDC 2012會話211詳細介紹了這一點,其中包括不同級別的隊列取消,優化等。這是一個很棒的視頻。 'cellForRow'中的 – jrturton 2012-07-23 09:54:58
,爲什麼不立即設置圖像爲零?這樣,它會暫時空白,而不是錯誤的圖像。 – user102008 2012-07-23 17:55:35
@ user102008我這樣做了,但它不起作用。錯誤的圖像已經在主線程中排隊(刷新處於執行過程中),等待顯示。 – 2012-07-23 22:05:49