如何在同一会话中使用不同的下载任务来下载多张图片

7
我正在尝试使用同一会话和不同的下载任务来下载多个图像,但是只能下载第一个图像。在didFinishDownloadingToURL中,我使用if条件来识别下载任务,并将其设置为特定的imageView。
以下是我的代码,请耐心等待:
@interface ViewController ()
{
    NSURLSessionConfiguration *sessionConfiguration;
    NSURLSessionDownloadTask *firstDownloadTask;
    NSURLSessionDownloadTask *secondDownloadTask;
    NSURLSession *session;
    UIImageView *firstImageHolder;
    UIImageView *secondImageHolder;
}
@end

- (void)viewDidLoad
{
            NSString *firstDownloadLink = @"http://letiarts.com/letiarts2014/wp-content/uploads/2014/04/icon_game.png";
            sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
            session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
            firstImageHolder = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
            [_viewImages addSubview: firstImageHolder];
            firstDownloadTask = [session downloadTaskWithURL:[NSURL URLWithString:firstDownloadLink]];
            [firstDownloadTask resume];

            //2
            NSString *secondDownloadLink = @"http://downloads.bbc.co.uk/skillswise/images/promo/prefab-maths-game-336x189.jpg";
            secondImageHolder = [[UIImageView alloc] initWithFrame:CGRectMake(50, 0, 45, 45)];
            [_viewImages addSubview: secondImageHolder];
            secondDownloadTask = [session downloadTaskWithURL:[NSURL URLWithString:secondDownloadLink]];
            [secondDownloadTask resume];
}

在didFinishDownloadingToURL方法中:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
    NSData *data = [NSData dataWithContentsOfURL:location];

    if (downloadTask == firstDownloadTask) {

            UIImage *theImage1 = [UIImage imageWithData:data];

            [firstImageHolder setImage:theImage1];

        NSLog(@"DOWNLOAD FIRST IMAGE FINISHED");

    }
    //download finished
    if (downloadTask == secondDownloadTask) {

            UIImage *theImage2 = [UIImage imageWithData:data];

            [secondImageHolder setImage:theImage2];

        NSLog(@"DOWNLOAD SECOND IMAGE FINISHED");

    }
}

非常感谢您提前阅读!


我认为你可以使用类似这样的东西:https://gist.github.com/lojals/aa786025684b227ab9ba 我用它来完成了这个项目:http://instagram.com/p/t_w6GdiBj-/ 你可以在这里查看整个项目:https://github.com/lojals/SeLeTiene - lojals
但是如果我有100张照片而不是2张呢?那我该怎么办?我在考虑使用for循环并在其外部声明会话和配置...所以我的问题是:在for循环内部使用相同的任务会有问题吗?还是需要一个新的任务? - Laur Stefan
实际上,我将我向您展示的代码放在FOR语句中,因此它将为每个下载创建不同的线程,因此是异步的。 就像这样 https://github.com/lojals/SeLeTiene/blob/master/Se%20Le%20Tiene/Views/ProductsContViewController.m#L90 如果您使用过UITableView或UICollectionView,则知道该方法每个单元格都会调用。 - lojals
2个回答

4
我看到你已经解决了自己的问题,但是我想补充一些内容。
  1. 下面这个实例只需具有以下属性即可,没有必要拥有太多属性。

@property NSURLSession * session;

此外,您可以通过taskIdentifier识别任务。

NSNumber * key = @(firstDownloadTask.taskIdentifier);

  1. 在委托中进行UI操作时需要小心,如果不从主线程调用可能会导致冻结。为了安全起见,应该使用:

dispatch_async(dispatch_get_main_queue(), ^{

[firstImageHolder setImage:theImage1];  

});

示例工作代码

@interface ViewController: ...<...>
@property (nonatomic, strong) NSURLSession *session;
@end

@implementation ViewController

- (void)viewDidLoad
{

        NSURLSessionConfiguration *sessionConfiguration;

        //NSURLSessionDownloadTask *downloadTask; //can use same task if cancelling is not intended.

        NSURLSessionDownloadTask *firstDownloadTask;
        NSURLSessionDownloadTask *secondDownloadTask;

        sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
        session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];

        //1
        NSString *firstDownloadLink = @"http://letiarts.com/letiarts2014/wp-content/uploads/2014/04/icon_game.png";
        firstImageHolder = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
        [_viewImages addSubview: firstImageHolder];
        /*downloadTask*/firstDownloadTask = [session downloadTaskWithURL:[NSURL URLWithString:firstDownloadLink]];
        [/*downloadTask*/firstDownloadTask resume];

        //2
        NSString *secondDownloadLink = @"http://downloads.bbc.co.uk/skillswise/images/promo/prefab-maths-game-336x189.jpg";
        secondImageHolder = [[UIImageView alloc] initWithFrame:CGRectMake(50, 0, 45, 45)];
        [_viewImages addSubview: secondImageHolder];
        /*downloadTask*/secondDownloadTask = [session downloadTaskWithURL:[NSURL URLWithString:secondDownloadLink]];
        [/*downloadTask*/secondDownloadTask resume];
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
    NSData *data = [NSData dataWithContentsOfURL:location];

    if (downloadTask.taskIdentifier == 1) {
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImage *theImage1 = [UIImage imageWithData:data];
            [firstImageHolder setImage:theImage1];
        });

        NSLog(@"DOWNLOAD FIRST IMAGE FINISHED");

    }
    //download finished
    if (downloadTask.taskIdentifier == 2) {
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImage *theImage2 = [UIImage imageWithData:data];
            [secondImageHolder setImage:theImage2];
        });

        NSLog(@"DOWNLOAD SECOND IMAGE FINISHED");

    }
}

@end

那我可以使用 for 循环来重新创建相同的 NSURLSessionDownloadTask 对象,只需要更改 URL 即可? - Laur Stefan
那会是什么样子呢?只是一个简单的for循环,具有相同的下载任务吗?我会将URL字符串放入数组中,并递增位置以更改数组。为什么不能取消任务呢? - Laur Stefan
数组就可以了,但是如果没有任务参照,你无法取消它。会话只有一起取消所有任务的API。要取消任何特定任务,需要任务参照。 - bllakjakk
非常感谢 @bllakjakk! - Laur Stefan
@ChetanKedawat 嘿,如果我有超过2张图片,没有UIImageView怎么办?我应该将它们存储在数组中吗? - Rajal

1
代码本身没有问题,问题在于我的实际代码中存在错误,在第二个简历中我调用了第一个任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接