2016-05-14 62 views
0

我试图从一个url加载图像。在cellForRowAtIndexPath中使用dispatch_async加载图像

以下是我的代码..

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 

    UITableViewCell *cell = nil; 

    cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@""]; 

    if (cell == nil) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
             reuseIdentifier:nil]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
    } 

    dispatch_async (dispatch_get_main_queue(), ^{ 

     NSData * storeImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:productImageArray[indexPath.row]]]; 

     self.productImage.image = [UIImage imageWithData:storeImageData]; 
     }); 

      [cell.contentView addSubview:self.productImage]; 

return cell; 
} 

的问题是,

  1. UI冻结,直到图像加载。
  2. 只有最后一个单元格正在加载图像,但其余单元格不加载图像。

我该如何解决这个问题?

+1

请参阅Apple的[LazyTableImages示例应用](https://developer.apple.com/library/ios/samplecode/LazyTableImages/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009394)。 – rmaddy

回答

1

@MGR,你可以使用调度异步,但有一个库https://www.cocoacontrols.com/controls/hanekeswift,一个优秀的图书馆。它会处理下载图像,它有一个方法来加载图像imageview.public func hnk_setImageFromURL(URL: NSURL, placeholder: UIImage? = default, format: Haneke.Format<UIImage>? = default, failure fail: ((NSError?) ->())? = default, success succeed: ((UIImage) ->())? = default)

它也具有缓存功能。所以你可以简单地在cellForRow中实现这个功能。多数民众赞成它的事情将由Haneke处理。

+0

兄弟...我怎样才能在目标c ..谢谢你 – Roger

+0

这个库也可用于目标c。使用cocoapods将此库下载到您的项目中。然后在你的cellForRow方法中使用。而已。 [imageView hnk_setImageFromURL:url]; – karthik

+0

有没有其他的选择? – Roger

1

尝试NSURLSessionTask

NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 
    if (data) { 
     UIImage *image = [UIImage imageWithData:data]; 
     if (image) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       UITableViewCell * cell = (id)[tableView cellForRowAtIndexPath:indexPath]; 
       if (cell) 
        cell. productImage.image = image; 
      }); 
     } 
    } 
}]; 
[task resume]; 
+0

它引发终止应用程序,由于未捕获的异常'NSInvalidArgumentException',原因:' - [__ NSCFString absoluteURL]:无法识别的选择器发送到实例0x155886fd0' – Roger

+0

@KaruppuMGR检查您的网址 –

+0

@KaruppuMGR如果您有更多的Web服务,我会建议您使用AFNetworking –

1

你是在主UI线程,这是造成画面冻结下载图像同步

请按照下面的文章来解决此问题:

iOS: How To Download Images Asynchronously (And Make Your UITableView Scroll Fast)

也回答你的第二个问题:

你似乎使用的cellForRowAtIndexPath方法之外实例化一个ImageView的,然后您试图将其添加到每个单元格中,这会导致图像从前一个单元格中移除,并添加到当前单元格中

因为视图只能有一个超级视图,并且一旦您尝试在其他视图中添加子视图,它将从其当前超级视图中删除

1

您可以使用GCD在后台线程中加载图像,如下所示:

//get a dispatch queue 

    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

    //this will start the image loading in bg 

    dispatch_async(concurrentQueue, ^{   
     NSData *image = [[NSData alloc] initWithContentsOfURL:imageURL]; 

     //this will set the image when loading is finished 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      imageView.image = [UIImage imageWithData:image]; 
     }); 
    }); 

但是,解决这些问题,最简单的解决方法是使用一个UIImageView类,如设有SDWebImageAFNetworking。如果你愿意,你可以编写你自己的代码来处理上述问题,但这是很多工作,上面的UIImageView类已经为你做了这个。

+0

仍然只加载最后一张图片 – Roger

1

试试这个:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
    cell.imageView.image = image; 

或者有时候我要做的就是更新模型,然后在特定indexPath重装电池:

myModel.image = downloadedThumbImage; 
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
            withRowAnimation:UITableViewRowAnimationNone]; 


    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
    static NSString *CellIdentifier = @"top50places"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    //getting the selected row image 
    NSDictionary* currentImageDictionary=[self.topfifty objectAtIndex:indexPath.row];//topFifty is an array of image dictionaries 

    UIImage *currentImage = [currentImageDictionary objectForKey:@"image"]; 

    if (currentImage) { 
     // we already fetched the image, so we just set it to the cell's image view 
    cell.imageView.image = currentImage; 
    } 
    else { 
     // we don't have the image, so we need to fetch it from the server 

    // In the meantime, we can set some place holder image 
    UIImage *palceholderImage = [UIImage imageNamed:@"placeholder.png"]; 
    cell.imageView.image = palceholderImage; 

    // set the placeholder as the current image to your model, so you won't 
    // download the image multiple times (can happen if you reload this cell while 
    // download is in progress) 
    [currentImageDictionary setObject:palceholderImage forKey:@"image"]; 

    // then download the image 
    // creating the download queue 
    dispatch_queue_t downloadQueue=dispatch_queue_create("thumbnailImage", NULL); 

    dispatch_async(downloadQueue, ^{ 
    UIImage *downloadedThumbImage=[self getImage:currentImageDictionary] ; 

    //Need to go back to the main thread since this is UI related 
    dispatch_async(dispatch_get_main_queue(), ^{ 
      // store the downloaded image in your model 
      [currentImageDictionary setObject:image forKey:@"image"]; 

      // update UI 
      UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
      cell.imageView.image = image;  
    }); 
    }); 
    dispatch_release(downloadQueue); 

    } 

return cell; 
} 
1

我觉得这是最好的方法异步下载图像。我会一直使用下面的方法来完成这个任务。

的cellForRowAtIndexPath:

NSURL *imgURL = [[NSURL URLWithString:productImageArray[indexPath.row]]; 
[self downloadImageWithURL:imgURL 
      completionBlock:^(BOOL succeeded, UIImage *image) { 
          self.productImage.image=image; 
    }]; 

并添加此方法

- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock 
{ 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] 
      completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
      if (!error) 
       { 
       data = [NSData dataWithContentsOfURL:url]; 
       UIImage *image = [[UIImage alloc] initWithData:data]; 
       completionBlock(YES,image); 
       } else{ 
       NSLog(@"Error in downloading image:%@",url); 
       completionBlock(NO,nil); 
       } 
      }]; 
} 

利用这一点,甚至我们可以更好地了解是否有在下载图像的任何问题。

+0

这里的一个问题,在主线程上使用异步任务不会阻塞UI? – Sravan