2012-07-23 3 views
4

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) { 
    }]; 
} 
+1

WWDC 2012 세션 211은 대기열 취소, 최적화 등의 다양한 수준으로이를 자세히 설명합니다. 멋진 동영상입니다. 'cellForRow'에 – jrturton

+0

이 있습니다. 이미지가 없으면 이미지를 nil로 설정하는 것이 어떻습니까? 그런 식으로, 그것은 틀린 심상 대신 일시적으로 공백 일 것이다. – user102008

+0

@ user102008 그랬지만 작동하지 않습니다. 잘못된 이미지가 메인 스레드에 이미 대기 중입니다 ('새로 고침'이 실행 중간에 있음). 표시 대기 중입니다. –

답변

1

좋아 (내 요구 사항은 서버에서로드 루프에서 이미지의 집합을 표시하는 것이기 때문에 나는 또한 SDWebImage을 사용할 수 없습니다) ... 그 작업을 수행하는 또 다른 방법은 넣어하는 것입니다 당신의 '이미지 코드를 요청', 당신의 AnimatedImageView INTO, 그리고 셀 클래스에서,

// your controller 
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
    ... 
    [cell.imageView setDistantImage:imageURL]; 
    ...  
    } 

그런 요청을 새 이미지의 URL을 설정할 때마다 출원 무효 'setDistantImage'는 ASIHttpRequest을 생성하고 이전

를 무효화 빠르고 긴 스크롤 모든 다운로드 한 이미지를 오버레이 재사용 세포와 CollectionView &있는 TableView에 많은 이미지를로드 할 때
//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... 
0

나는 똑같은 문제를 가지고 있었다.

TableView의 경우 'didEndDisplayingCell'메서드가 제공된 WWDC 2012를 살펴 보았지만이 메서드가없는 CollectionView에는 유용하지 않았습니다. :. 마지막으로 (

O를, 내가 모두 ... 다행히에 대한 해결책을 발견 을 아이디어는 그 담당 될 것이다 클래스에게있는 TableView 또는 CollectionView와의 세포에 의해 호출 하여 ImageLoader을 만들 이다 . 구현에 다음 함수를 추가, 그리고

@interface ImageLoader() { 
__block NSURLSession *_session; 
} 

:

다운로드 이미지
구현에 은 세계의 나머지 부분에 변수를 숨기려면이 조각을 추가
- (void)getViewForCell:(UIImageView*)cell 
       FromURL:(NSURL*)url { 

NSBlockOperation *_loadImageOp; 
__block NSOperationQueue *_opQueue; 

_opQueue = [[NSOperationQueue alloc]init]; 

if (_session != nil) { 
    [_session invalidateAndCancel]; 
} 

_loadImageOp = [[NSBlockOperation alloc]init]; 
[_loadImageOp addExecutionBlock:^{ 

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; 
    _session = [NSURLSession sessionWithConfiguration:config 
              delegate:nil 
             delegateQueue:_opQueue]; 

    NSURLSessionDownloadTask *downloadTask = [_session downloadTaskWithURL:url 
                 completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { 
     UIImage *imageCell = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]]; 

     if (imageCell) { 
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
       cell.image = imageCell; 
      }]; 
     } else { 
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
       cell.image = [UIImage imageNamed:@"imageNotWorking.png"]; 
      }]; 
     } 
    }]; 

    [downloadTask resume]; 
}]; 

[_opQueue addOperation:_loadImageOp]; 
} 

아이디어는 1 /.입니다. 멤버 변수 _session이 downloadTask, 2 /를 통해 들어오는 매개 변수에 지정된 URL을 가져 오는 블록을 만듭니다. mainQueue를 통해 다운로드 한 이미지를 사용자 인터페이스에 표시합니다. 3 /. 초기 생성 된 블록은이 특정 재사용 셀 전용 큐에 추가됩니다.

중요한 점은 멤버 변수가 nil이 아닌 경우 'invalidateAndCancel'함수가 호출됩니다. 셀을 다시 사용할 때마다 이전 세션에서 마지막 이미지를 가져 오지 않고 들어오는 매개 변수 'url'. 이후

, 하는 것을 잊지 마세요이 방법으로 호출 할 각 재사용 세포 2/국지적 인 방법에 대해 하나에서는 imageLoader를 사용하기 위해 당신의 TableView/CollectionView 세포 클래스에서 1/국지적 인 다음 코드를 넣어 '있는 tableView : cellForRowAtIndexPath :'당신의 CollectionView의 /의 TableView :

한 번 수행
@interface TableCell() { //...or CollectionCell :o) 
ImageLoader *_imgLoader; 
} 
@end 

@implementation TableCell 
- (instancetype)initWithCoder:(NSCoder *)aDecoder { 
self = [super initWithCoder:aDecoder]; 
_imgLoader = [[ImageLoader alloc]init]; 
return self; 
} 

- (void)imageURL:(NSURL*)url { 
[_imgLoader getViewForCell:self.imageViewWhereTheDownloadedImageIs 
        FromURL:url]; 
} 
@end 

, 단지 방법 [cell imageURL:url] 전화 '를 tableView를 : cellForRowAtIndexPath :'당신의 CollectionView /의 TableView의.

이제 원하는대로 빠르게 스크롤 할 수 있으며 항상 올바른 이미지와이 이미지 만 표시합니다.

나는 그것이 도움이되기를 바랍니다. : o)

관련 문제