从包含url的数组中添加图片到单元格的imageView – iOS Xcode对象C

只是为了更好地了解这篇文章的内容,最终会在这个问题上结束:

如何从任意数量的url中asynchronous下载预定义数量的图像,将它们添加到字典(或数组,如果更容易),以便按照下载开始的顺序添加它们,而不是按顺序添加它们他们完成了?

这是这篇文章的主要问题,但是为了好的措施,并且让我理解我的意思,我在下面的文章中join了涉及这个问题的具体案例。 我知道这很长,但解释我的情况却相当复杂。

所以,这里什么都不做:

我有一个tableView从不同的数组加载一些事情。 每次启动应用程序时,所有数组都是从JSON获取中创build的,我的想法是通过更新JSON文本文件来更新应用程序中的信息。 JSON文本文件中的一个条目包含URL的图像,我想要添加到tableView单元格的contentview。 我得到了JSON获取工作,并创build了包含来自提取信息的字典“dataDictionary”。

然后,数组创build像这样:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { // Array is created from the dictionary created from the JSON fetch _dataArray = _dataDictionary[@"games"]; // Arrays that will eventually hold info from JSON file is created _Titles = [[NSMutableArray alloc] init]; _Descriptions = [[NSMutableArray alloc] init]; _Date = [[NSMutableArray alloc] init]; //images will be added to dictionary instead _imageDict = [[NSMutableDictionary alloc]init]; // Info parsed from the JSON fetch, is now added to arrays for (NSDictionary *eachData in _dataArray) { _Title = eachData[@"Title"]; _Description = eachData[@"Description"]; _Date = eachData[@"Release"]; // Key for image url is created _image = eachData[@"ImageLink"]; [_Titles addObject:_Title]; [_Descriptions addObject:_Description]; [_Dates addObject:_Date]; 

现在,下面有更多的代码,这是我处理图像的地方(将在这个简短的解释和下面的代码示例之后),你可以看到我已经为JSON中的ImageLink条目指定了一个名为“image”的键。 现在我调用这个方法,开始asynchronous下载图像:

 - (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 ) { UIImage *image = [[UIImage alloc] initWithData:data]; completionBlock(YES,image); } else{ completionBlock(NO,nil); } }]; } 

这个方法在下面的代码中被调用,所以继续之前的代码:

 // Just to be clear, we are now back in the "for (NSDictionary *eachData in _dataArray)" statement from the first code sample //calling the above method here [self downloadImageWithURL:[NSURL URLWithString:_image] completionBlock:^(BOOL succeeded, UIImage *image) { if (succeeded) { //All this code runs when an image is successfully downloaded NSLog(@"image download succesfull"); UIImage *downloadedImage = [[UIImage alloc] init]; // Doing this so I can resize the downloaded image to a proper size downloadedImage = image; //long boring code to resize image here UIImage *resizedImage = [[UIImage alloc] init]; // resizedImage is as the name implies, the resized image that now has a proper size for the cell's content view _number++; //Int that start out as -1, this increments each time an image is downloaded to allow the images to be added to the dictionary with the keys 0, 1, 2... // Wrapping the int in a NSNumber NSNumber *number = [NSNumber numberWithInt:_number]; // Turning the NSnumber into a string NSString *key = [number stringValue]; // Images finally being added to the dictionary, but, in the wrong "order" - or rather, with the wrong keys / numbers [_imageDict setObject:resizedImage forKey:key]; //Update tableView when images are added to dictionary if (_imageDict.count == _gameTitles.count) { [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; } } }]; //Update tableView when data is added to array, this is to allow info to be shown even before the images are done downloading if (Titles.count == _dataArray.count) { // Update tableView with loaded content [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; } } // "for" statement ends here } 

总结最重要的部分:

当填充tableView中的单元格时,我使用indexPath.row从每个数组中获取适当的信息。 下载的图像,我把它们添加到字典与0,1,2键..然而,当完成,因为下载是asynchronous下载没有完成它的初始化顺序,而是,较小的图像得到(并不奇怪)首先下载并添加到图像字典。 这意味着图像的键不符合我所有其他数组中的顺序,因此使用indexPath.row在第一个单元格中设置图像只需设置首先下载的图像,而不是首先启动的图像下载。 基本上,即使图像5首先被下载,它应该添加键“4”,而不是“0”。

我还应该提到,由于JSON获取,我不知道有多less图片将被预先下载,因为这可以改变取决于JSON。 这在stackoverflow(以及其他地方)取消了很多答案。

所以,所有这些文本和代码,什么都不会导致开始的问题,我如何从任意数量的urlasynchronous下载一个不预先定义数量的图像,将它们添加到字典(或数组,如果更容易),以便它们被添加下载开始的顺序,而不是按顺序添加它们?

非常感谢您花时间阅读本文。

所以,所有这些文本和代码,什么都不会导致开始的问题,我如何从任意数量的urlasynchronous下载一个不预定义数量的图像,将它们添加到字典(或数组,如果更容易),以便它们被添加下载开始的顺序,而不是按顺序添加它们?

您可以使用SDWebImage Library下载图像,它从给定的URLasynchronous下载您的图像,它也caching图像和pipe理所有的东西给你,这是非常受欢迎的。所有你需要做的是将下面的代码添加到你的-cellForRowAtIndexPath委托方法:

 [cell.imageView sd_setImageWithURL:[NSURL URLWithString:imageURLThatYouGetFromJSONResponse] placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; 

此外,我build议你不要使用数组或字典。你可以将所有的信息存储在一个对象中。在许多情况下,这很容易和最好的实践,并称为面向对象的方法。你创build一个NSObject的子类,并在那里创build属性“标题“,”描述“,”名称“,”图像URL“。你可以按照这个OOP教程进行一些更好的理解。

您不关心图像的数量,因为您定义了-numberOfRowsInSection的行数,并且-cellForRowAtIndexPath被称为您在-numberOfRowsInSection写入的次数。您可以添加:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [arrayOfYourObjects count]; } 

编辑:如何使用SDWebImage处理图像?

答:您可以使用SDWebImageManager,它也为您pipe理caching

 SDWebImageManager *manager = [SDWebImageManager sharedManager]; [manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { // progression tracking code } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (image) { // Code to resize //After resizing cell.imageView.image = resizedImage; } }];