如何在iOS中异步下载多个图像而不影响UI?

时间:2013-12-02 09:11:07

标签: ios multithreading image asynchronous

我有100个网址,我想下载所有这些图片并保存在文档中。为了保存我已经完成,我也可以进行延迟加载,但我无法以最短的时间下载所有内容,GUI不应该挂起。

这样做的合适方法是什么?

由于

4 个答案:

答案 0 :(得分:3)

使用SDWebImage。您可以从以下网址下载

https://github.com/rs/SDWebImage

使用异步请求

加载100个图像
for(int i=0; i<99; i++)
{
    strImage=[[res valueForKey:@"result"] objectAtIndex:i];
    if ([[strImage lowercaseString] hasSuffix:@".jpg"] || [[strImage lowercaseString] hasSuffix:@".png"])
    {
        //[HUD show:YES];
        NSURL *url=[[NSURL alloc]initWithString:strImage];
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
        [NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
        {
             thumbnail.image=[UIImage imageWithData:data];
        }];
    }
}

答案 1 :(得分:3)

复杂的解决方案可能会变得非常复杂。下载和保存100个URL并不像下载一个图像那样容易100次。

在雄心勃勃但不太聪明的实施中出现的最棘手的问题是内存压力。第三方网络库不会自动为您解决此问题。

一种简单但可行的方法是尝试以性能为代价来避免内存问题,正在执行下载并将所有顺序保存到磁盘操作。这可确保在任何时候只处理一个图像。因此,您可以对此方法所需的最大内存进行安全假设。

解决方案可能如下所示:

假设您有一个异步方法,它从给定的URL加载图像数据:

typedef void (^load_completion_t)(NSData* data, NSError* error);
- (void) loadURL:(NSURL*)url completion:(load_completion_t)completionHandler;

此方法将整个图像数据加载到内存中。这不是最好的方法,但是IFF我们可以假设一个图像总是适合内存,它就变成了一个简单的解决方案。

此外,假设有一种将数据保存到磁盘的同步方法:

- (void) saveData:(NSData*)data;

现在,给定一个URL数组,您可以按顺序加载并保存大量图像,如下所示:

typedef void(^completion_t)(id result, NSError* error);

- (void) saveImagesWithURLs:(NSMutableArray*)urls 
         completion:(completion_t)completionHandler
{
    if ([urls count] > 0) {
        NSURL* url = [urls firstObject];
        [urls removeObjectAtIndex:0];
        [self loadURL:url completion:^(NSData* imageData, NSError*error){
            if (imageData) {
                [self saveData:imageData];
                [self saveImagesWithURLs:urls completion:completionHandler];
            } 
            else  {
               // handle error
            }
        }];
    }
    else {
        // finished
        if (completionHandler) {
            completionHandler(@"Images saved", nil);
        }
    }
}

上面的方法是“异步循环”:

loadURL:completion的完成处理程序将调用saveImagesWithURLs:completion:,就像递归调用一样。但是,这不是一个递归方法:当方法saveImagesWithURLs:completion:的完成处理程序执行时,saveImagesWithURLs:completion:已经返回。

鉴于属性是一系列URL:

@property (nonatomic, strong) NSArray* imageURLs;

您可以调用异步循环,如下所示:

[self saveImagesWithURLs:[self.imageURLs mutableCopy] 
              completion:^(id result, NSError*error){
    if (error) {
        // handle error
    }
    else {
        // result equals @"Images saved"
    }
}];

您可以从主线程调用此方法。它不会阻塞,因为它是异步的。我们还假设,完成处理程序将在私有队列上调用,而不是在主线程上调用。

答案 2 :(得分:0)

更好的用户AFNetworking,它将帮助您异步下载所有图像(无GUI挂起)

https://github.com/AFNetworking/AFNetworking

答案 3 :(得分:0)

您可以使用 AFHTTPClient enqueueBatchOperations,这有一个completionBlock,在所有操作完成后调用。应该是你正在寻找的。