0

느린 로딩 이미지는 내 collectionView의 고르지 못한 느린 효과 뒤에있었습니다. 나는 하루 종일 다양한 Q 글을 읽고있다. &. 이 문제를 해결하는 가장 좋은 방법은 cellForItemAtIndexPath에 필요한 데이터를 사전로드하여 필요한 정보를 얻을 수있게하는 것입니다.UICollectionView에서 어떻게 내부에서 사용할 cellForItemAtIndexPath 외부의 데이터를 미리로드 할 수 있습니까?

나는 이것을 어떻게 할 수 있는지 잘 모르겠습니다. 내 백엔드로 구문 분석을 사용하고 있지만 확실한 예가 주어진다면이를 수행하는 방법을 알아낼 수 있을지 확신합니다. 지금까지 본 것부터 데이터를 가져 오는 별도의 방법이 필요합니다.

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView 
{ 
    return 1; 
} 


-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 
{ 
    return [[self objects] count]; 
} 

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object 
{ 
    NSArray *people = [self objects]; 
    static NSString *CellIdentifier = @"Cell"; 

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


    PFObject *current; 

    current = [people objectAtIndex:indexPath.item]; 

    PFFile *userImageFile = current[@"image"]; 

    [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) { 
     UIImage *image = [UIImage imageWithData:imageData]; 

     [[cell contentView] setContentMode: UIViewContentModeScaleAspectFit]; 
     [[cell imageView] setImage:image]; 

    }]; 

    [[cell title] setText:[current valueForKey:@"title"]]; 
    [[cell price] setText:[NSString stringWithFormat: @"£%@", [current valueForKey:@"price"]]]; 

    return cell; 

} 

그래서 어쩌면 cellForItemAtIndexPath 그 메서드를 호출하고 무엇을 필요로하는지 취할 필요가 : 여기

는 코드입니다. 데이터가 이미 사용 가능하므로 cellForItemAtIndexPath 메소드에로드 할 필요가 없으며 셀이 즉시 채워집니다.

제안 사항과 예제를 제공해주십시오.

이미지를 확인하는 것이 좋을 것이라고 말했고, 존재하지 않는다면 자리 표시자를 제공하고, 존재한다면 설정합니다. 위의 코드가 변경되었습니다.

업데이트 :

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object 
{ 

    NSArray *people = [self objects]; 

    static NSString *CellIdentifier = @"Cell"; 

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



    PFObject *current; 

    current = [people objectAtIndex:indexPath.item]; 



    PFFile *userImageFile = current[@"image"]; 

    [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) { 

     if (!error) 
     { 

      if (!image) { 
       [[cell imageView] setImage:[UIImage imageNamed:@"placeholder.png"]]; 


      } else { 

       image = [UIImage imageWithData:imageData]; 


       //resize image 
       CGSize destinationSize = CGSizeMake(158,187); 
       UIGraphicsBeginImageContext(destinationSize); 
       [image drawInRect:CGRectMake(0,0,destinationSize.width, destinationSize.height)]; 

       //New image 
       UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext(); 
       UIGraphicsEndImageContext(); 

       //Optimise image 
       NSData *imageDataCompressed = UIImageJPEGRepresentation(newImage, 0.4f); 
       // NSLog(@"Image Size %@", NSStringFromCGSize(newImage.size));//log size of image 
        NSLog(@"%@", [current valueForKey:@"title"]); 


       [[cell imageView] setImage:[UIImage imageWithData:imageDataCompressed]]; 



      } 

     } 

    }]; 


    [[cell title] setText:[current valueForKey:@"title"]]; 
    [[cell price] setText:[NSString stringWithFormat: @"£%@", [current valueForKey:@"price"]]]; 


    return cell; 

} 

플레이스 홀더가 잘 표시하지만 남아, 이미지가 그래서 내 세포가를 반영 할 수로드 된 경우 어떻게 알 수 있습니까?

감사합니다. 친절하게 생각합니다.

업데이트 :

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object 
{ 

    NSArray *people = [self objects]; 

    static NSString *CellIdentifier = @"Cell"; 

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

    [cell.activityIndicator startAnimating]; 

    PFObject *current; 

    current = [people objectAtIndex:indexPath.item]; 



    PFFile *userImageFile = current[@"image"]; 

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:userImageFile.url, indexPath.item]]; 
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url                 cachePolicy:NSURLRequestReturnCacheDataDontLoad 
        timeoutInterval:6.0]; 
        [cell.imageView setImageWithURLRequest:urlRequest 
        placeholderImage:[UIImage imageNamed:@"placeholder.png"] 
        success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { 

        //resize image 
        CGSize destinationSize = CGSizeMake(158,187); 
        UIGraphicsBeginImageContext(destinationSize); 
        [image drawInRect:CGRectMake(0,0,destinationSize.width, destinationSize.height)]; 

        //New image 
        UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext(); 
        UIGraphicsEndImageContext(); 

        //Optimise image 
        NSData *imageDataCompressed = UIImageJPEGRepresentation(newImage, 0.4f); 

        cell.imageView.image = [UIImage imageWithData:imageDataCompressed]; 
        NSLog(@"Image Size %@", NSStringFromCGSize(newImage.size));//log size of image 
        [cell.activityIndicator stopAnimating]; 

        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError   *error) { 
        NSLog(@"Failed to download image: %@", error); 
             }]; 




    return cell; 

} 

최근 업데이트 :

변경 가능한 배열 후 NSMutableDictionary parse.com에 저장 데이터를 얻는 방법을 설정한다. 나는 옷의 이미지에 제목, 가격 및 URL을 저장합니다.

- (void)grabDataFromCloud 
{ 

    self.model = [NSMutableArray array]; 
    for (PFObject *object in [self objects]) { 
     PFFile *imageFile = [object valueForKey:@"image"]; 
     NSURL *url = [NSURL URLWithString:imageFile.url]; 

     NSMutableDictionary *newObject = [NSMutableDictionary dictionaryWithDictionary:@{@"title": [object valueForKey:@"title"], @"price": [object valueForKey:@"price"], @"imageUrl": url}]; 
     [[self model] addObject:newObject]; 
    } 
} 

이것은 내 cellForItemsAtIndexPath 메소드에서 호출됩니다.

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object 
{ 

    [self grabDataFromCloud]; 
    static NSString *CellIdentifier = @"Cell"; 

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

    [cell.activityIndicator setHidden:YES]; 

    NSMutableDictionary* d = [self.model objectAtIndex:indexPath.item]; 
    cell.title.text = d[@"title"]; 
    cell.price.text = [NSString stringWithFormat:@"£%@", d[@"price"]]; 

    if (d[@"image"]) { 
     cell.imageView.image = d[@"image"]; 
    } else { // if not, download it 
     cell.imageView.image = nil; 

     dispatch_queue_t backgroundQueue = dispatch_queue_create("test", 0); 

     dispatch_async(backgroundQueue, ^{ 

      NSData* data = [NSData dataWithContentsOfURL:d[@"imageUrl"]]; 
      UIImage* img = [UIImage imageWithData:data]; 
      d[@"image"] = img; 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        //causes crash Assertion failure in -[UICollectionView _endItemAnimations], 
        // /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:3687 
        // [self.collectionView reloadItemsAtIndexPaths:@[indexPath]]; 
       }); 
     }); 

    } 

     return cell; 
    } 

답변

0

며칠 후 내 이미지가 너무 큽니다. 나는 그것들의 크기를 조정해야했고, 즉시이 문제를 해결했다.

필자는 문자 그대로 문자의 범위를 좁히고 내 이미지를 검사하여 크기를 조정한다고 생각했던 방법으로 크기가 조정되지 않았 음을 확인했습니다. 이것이 내가 테스트에 익숙해 져야하는 이유입니다.

지난 몇 일간 GCD와 캐싱에 대해 많은 것을 배웠지 만이 문제는 훨씬 빨리 해결되었을 수 있습니다.

1

내가 AFNetworkingUIImageView+AFNetworking 범주를 사용하도록 건의 할 것입니다. 자리 표시 자 등을 자동으로 처리하고 백그라운드 스레드에서 모든 작업을 수행하여 주 스레드가 차단되지 않도록합니다. 구체적으로 말하면 다음과 같이 전화 할 방법입니다.

- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage; 
+0

나는 이것을 작동 시키려고 노력 해왔다. 캐싱과는 별도로 작업하고있다. cachepolicy를 NSURLRequestReturnCacheDataElseLoad로 설정 했는데도 이미지가 계속 다시 다운로드됩니다. 이미지가 다운로드 된 것처럼 보이지만 스크롤 할 때 나는 여전히 도려내 기 효과를 얻습니다. – LondonGuy

0

다른 접근 방법을 제안합니다.

Google for - 또는 SO - Asynchrnous 로딩에 대한 검색을 사용하십시오. 거의 모든 앱 프로그래머가이 문제를 조기 또는 이후에 직면합니다. 결과적으로 수많은 튜토리얼이 있습니다.

이 중 하나입니다. http://www.markj.net/iphone-asynchronous-table-image/ 나는 그것이 UICollectionView보다 오래되었고 그게 UITableView에 대해 설명한다고 생각합니다. 두 데이터 원본 대리자는 서로 가깝기 때문에 컬렉션에 쉽게 솔루션을 적용 할 수 있습니다.

귀하의 목표를 능률화하는 방법이 있습니다. 그러나 나는이 방법이 좋은 출발점이라고 생각한다. 나중에 일반적으로 접근법을 준수 할 수있게되면 솔루션을 리팩토링 할 수 있습니다.

+0

잘못된 페이지로 된 페이지를 확인했습니다. 나는 그 코드를 살펴 보았다. 나는해야 할 일이 무엇인지를 이해합니다. 그것은 그것을하는 법입니다. 지금 내 cellForItemAtIndexPath는 URL을 사용하여 항목을 가져옵니다. 그런 다음 그들은 캐싱되고 있지만 도마뱀은 여전히 ​​일어나고 있습니다. 나는 이미지를 축소했고 효과가 없다. – LondonGuy

+0

URL을 사용하여 URL을 가져올 때 비동기 적으로 수행합니까? –

+0

나는 확신한다. 제 질문 코드의 최신 업데이트를 확인하십시오. 이것은 최신 코드를 보여줍니다. – LondonGuy

1

이있는 자리 표시 자 이미지를 제공하기 위해 당신에게 달려 (또는 전무) 이미지가있을 때 필요하고 다운로드를 시작하고,이 수 있도록 다운로드되면 다음 에 이미지에 걸어 최초 그 후 즉시 을 제공 할 수 있습니다.. 이 예제는 테이블 뷰에 대한 것이지만 원칙은 완전히 동일합니다. 중요한 점은 내 데이터 모델은 NSMutableDictionary 객체 다. 사전에있는 그림의 URL뿐만 아니라 이미지를 유지하기위한 장소 인 각 사전 을 가지고있다.

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 
    NSMutableDictionary* d = (self.model)[indexPath.row]; 
    cell.textLabel.text = d[@"text"]; 
    if (d[@"im"]) { // if we have a picture, supply it 
     cell.imageView.image = d[@"im"]; 
    } else if (!d[@"task"]) { // if not, download it 
     cell.imageView.image = nil; 
     NSURLSessionTask* task = [self.downloader download:d[@"picurl"] 
             completionHandler:^(NSURL* url){ 
      if (!url) 
       return; 
      NSData* data = [NSData dataWithContentsOfURL:url]; 
      UIImage* im = [UIImage imageWithData:data]; 
      d[@"im"] = im; 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
      }); 
     }]; 
    } 
    return cell; 
} 
+1

그리고 그 코드는 당신 자신의 머신에서 실행될 수있는 완전한 다운로드 가능한 예제 코드 프로젝트에서 가져 와서 실제로 작동한다는 것을 볼 수 있습니다 (물론 테이블 뷰의 경우) : https://github.com/mattneub/Programming-iOS -Book-Examples/tree/master/bk2ch24p842downloader/ch37p1099downloader – matt

+0

잠시 동안 실험 해 보았습니다. 나는 mutable에 저장되어있는 NSDictionary에 내 데이터를로드한다. 이것은 모두 cellForItemAtIndex 메소드에 의해 트리거되는 메소드에 배치됩니다. 제목 및 가격은 잘 업데이트됩니다. 나는 이미지를 확인하고 거기에 없으면 하나 추가하려고한다. 내 img var 이미지가 실제로 거기에 있는지 확인하려면 예 이미지가 var에 저장됩니다. 제가 지금 가지고있는 마지막 문제는 그 이미지가 셀에 보여지는 것입니다. indexpaths에서 행을 다시로드하려고 시도했지만 앱이 충돌합니다. dispatch_get_main_queue의 위 코드에서 오류 메시지를 볼 수 있습니다. – LondonGuy

+0

1 ~ 2 분 후에 앱 자체가 충돌합니다. – LondonGuy

관련 문제