2013-04-29 5 views
4

사용자 정의 UICollectionViewCellUICollectionView 구현이 있습니다. 데이터 배열이 인터넷에서 가져 오지만 사용자가 콘텐츠에 액세스 할 때 이미지가 다운로드됩니다.UICollectionView에서 GCD 및 셀 재사용

이것은 아마도 가장 효율적인 방법은 아니지만 이런 식으로 남겨 둘 계획은 아니지만 문제 해결에 어려움을 겪었습니다. 세포가 "캐시 된"또는 "오래된"이미지를 표시하고 있으며 천천히 컬렉션보기를 스크롤하면 셀 이미지가 계속 변경됩니다.

이것은 실제 셀 이미지가 그 순간 그 순간에 사용할 수없는 문제 일 수 있으며 내 질문은 어떻게 빈 셀 또는 일부 활성 활성 모니터를 강제로 표시하고 잘못된 이미지를 표시하지 않는 것입니까? 사전에

감사합니다, 피니언

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
static NSString * CellIdentifier = @"Event"; 

EventCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; 


NSString *title = [[events objectAtIndex:indexPath.item] objectForKey:@"title"]; 
NSString *imageUrl = [[[events objectAtIndex:indexPath.item] objectForKey:@"photo"] objectForKey:@"url"]; 


dispatch_queue_t imageFetchQ = dispatch_queue_create("image fetched", NULL); 
dispatch_async(imageFetchQ, ^{ 

    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]; 

    if (imageData) 
    { 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      cell.eventImage.image = [UIImage imageWithData:imageData]; 
      cell.eventTitle.text = title; 

     }); 
    } 
}); 


return cell; 

} 
+0

대신이 튜토리얼에서와 같이 NSOperationQueue를 사용하는 것이 좋습니다. http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues –

+0

자습서를 따르려고했으나 재사용 문제는 실제로 다루지 않습니다. NSOperationQueue가 그런 솔루션에 들어갈 수있는 곳을 보았지만 문제는 그대로 남아 있습니다.어떤 이미지가 셀당 표시되는지 확인하는 메커니즘의 일부 유형을 구현해야한다고 생각합니다. 방법 그러나 확실하지 않은. 아직. – Pinion

답변

4

이것은 일반적인 문제입니다. 큰 문제는 셀의 이미지가 도착할 때까지 셀이 재활용되어 다른 일부 항목에 사용될 수 있다는 것입니다. 이미지를 마지막으로 사용할 수있는 셀의 이미지를 설정하려고하면 잘못된 항목에 대해 이미지를 설정하게됩니다.

따라서 셀을 직접 업데이트하지 마십시오. 이미지 다운로드 완료 블록에서 셀 참조를 유지하지 마십시오. 대신 완료 블록이 어떻게 보이는지에 관계없이 데이터 모델을 업데이트하도록하십시오. 컬렉션 뷰에 약한 참조를 유지하고 셀의 인덱스 경로를 저장할 수도 있습니다. 이미지가 도착하면 완료 코드는 -reloadItemsAtIndexPaths:을 호출 할 수 있습니다. 그러면 셀이 여전히 표시되어 있으면 콜렉션 뷰가 영향을받는 인덱스 경로의 셀을 다시로드합니다. 귀하의 -collectionView:cellForItemAtIndexPath: 방법은 평범한 일을하지만 이번에는 이미지를 데이터 모델에서 사용할 수 있습니다. 나는 당신의 데이터 모델이 어떻게 생겼는지 알 수 없기 때문에 나는이 정확한 코드를 테스트하지 않았습니다

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString * CellIdentifier = @"Event"; 
    EventCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; 

    Event *event = [events objectAtIndex:indexPath.item]; // replace "Event" with whatever class you use for your items 
    cell.eventTitle.text = [event objectForKey:@"title"]; 
    cell.eventImage.image = [event objectForKey:@"image"]; 
    if (cell.eventImage.image == nil) { 
     NSString *imageUrl = [[[events objectAtIndex:indexPath.item] objectForKey:@"photo"] objectForKey:@"url"]; 

     dispatch_queue_t imageFetchQ = dispatch_queue_create("image fetched", NULL); 
     dispatch_async(imageFetchQ, ^{ 
      __weak UICollectionView *weakCollection; 
      NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]; 
      UIImage *image = [UIImage imageWithData:imageData]; 
      if (image) 
      { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [event setObject:image forKey:@"image"]; // updating the model here 
        [weakCollection reloadItemsAtIndexPaths:@[indexPath]]; 
       }); 
      } 
     }); 
    } 
    return cell; 
} 

:

그래서, 당신의 코드처럼 보일 것입니다. 내가 생각한 클래스 Event에 대해 자신의 데이터 항목 클래스를 대체해야합니다. 그러나, 나는 내 자신의 코드에서 같은 기술을 사용하며, 이것이 올바른 방법이라고 생각한다. 하이라이트 :

  • 데이터 모델에서 이미지를 업데이트한다는 것은 다음에 이미지를 다운로드 할 때 항목이 보이지 않아도 항목을 표시해야 할 때 사용할 수 있음을 의미합니다.
  • 컬렉션보기에 약한 참조를 사용하면 사용자가 컬렉션보기에서 다른 곳으로 이동할 때 이미지가 계속 도착하는 경우 문제가 방지됩니다.
  • -reloadItemsAtIndexPaths:을 호출하면 ...cellForItemAtIndexPath: 방법으로 셀의 변경을 제한하는 데 도움이됩니다.

한 가지주의 할 점은 표시된 항목 목록이 변경 될 수있는 경우 (예 : 사용자가 시간 경과에 따라 항목을 추가하거나 삭제할 수있는 경우) 완료 코드가 인덱스 경로는 동일하게 유지됩니다. 이 경우 이미지가 도착할 때 항목의 색인 경로를 결정해야합니다.