如何使用NSURLSession从Objective-C中的服务器下载100个图像

时间:2018-06-14 01:27:32

标签: ios objective-c networking nsurlsession

我正在制作应用..

我需要从服务器下载很多图片,但我不知道该怎么做

以前是通过以下一些文章

来做到这一点的

目前正面临一些问题  当滚动图像闪烁并一直改变时。快速向上滚动时,所有图像都是错误的。我该怎么办?

- (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);
                                }
                           }];
}



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"venue";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
    }

    Venue *venue = ((Venue * )self.venues[indexPath.row]);
    if (venue.userImage) {
        cell.imageView.image = venue.image;
    } else {
        // set default user image while image is being downloaded
        cell.imageView.image = [UIImage imageNamed:@"default.png"];

        // download the image asynchronously
        [self downloadImageWithURL:venue.url completionBlock:^(BOOL succeeded, UIImage *image) {
            if (succeeded) {
                // change the image in the cell
                cell.imageView.image = image;

                // cache the image for use later (when scrolling up)
                venue.image = image;
            }
        }];
    }
}

**任何最佳方式建议**

1 个答案:

答案 0 :(得分:1)

我在您的代码中看到了一些问题,所以让我先给出一个您需要的最小例子:

- (void)downloadImageFrom:(NSURL *)path completion:(void (^)(UIImage *image))completionBlock {
    dispatch_queue_t queue = dispatch_queue_create("Image Download", 0);
    dispatch_async(queue, ^{
        NSData *data = [[NSData alloc] initWithContentsOfURL:path];
        dispatch_async(dispatch_get_main_queue(), ^{
            if(data) {
                completionBlock([[UIImage alloc] initWithData:data]);
            } else {
                completionBlock(nil);
            }
        });
    });
}

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

    MyTableViewCell *cell = ...; // Create my own cell
    NSString *imageURL = ...; // Get from my model

    cell.imageURLString = imageURL;
    [self downloadImageFrom:[NSURL URLWithString:imageURL] completion:^(UIImage *image) {
        if(cell.imageURLString == imageURL) {
            cell.imageView.image = image;
        }
    }];
    return cell;
}

首先,下载时(无论您使用什么)确保您使用正确的线程。我使用最简单的工具来下载使用NSData的远程图像,并且只要您的请求不需要额外的数据(如凭据),它就会很好用。您没有理由更改它,但确保在主线程上调用完成。

接下来您遇到的问题是多线程加上单元格出列问题。在表格视图中,将重用相同的单元格。向下滚动从屏幕向上移动的单元格将显示在底部。这是为了获得表现。

现在因为您向上和向下滚动并且图像异步加载,可能会调用完成块if (succeeded) {以查看它看起来不正确的单元格。您需要做的是检查通话是否仍然有效。

因此,您应该对您的单元格进行子类化,并至少添加一些标识符,例如imageURLString。您在进行调用之前设置了获取图像,然后在完成时再次检查单元标识符是否仍然相同。如果不是,那么您的单元格已被重用,下载的图像将被丢弃。

这也意味着你应该创建某种图像缓存。这样一个抛弃的图像并没有被丢弃,而是被缓存,如果出现相同的单元格,则不会再次发生下载。