将图像从URL保存到iOS目录

时间:2013-08-12 00:37:24

标签: ios objective-c

我想将大量(800-2000)图像从服务器保存到iPhone应用程序目录(文档目录)。

首先,我必须检查这些图像是否已经在iPhone目录中。

我使用此代码下载一张图片:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
[NSURLConnection connectionWithRequest:request delegate:self];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"pkm.jpg"];
NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
[thedata writeToFile:localFilePath atomically:YES];

请帮助我,任何建议:  1.在iPhone目录中保存原始名称的所有图像,而不是“pkm.jpg”  2.使用名称保存图像:从05052008321_bigger到05052008350_bigger  3.检查图像是否已下载,请勿再次下载。

我知道,也许这不仅仅是一个问题。但是一些建议,指示会非常好。

提前致谢。

2 个答案:

答案 0 :(得分:2)

一些反应:

  1. 您正在发起NSURLConnection connectionWithRequest(触发NSURLConnectionDataDelegate方法),但您显然忽略了这一点并发起了dataWithContentsOfURL。你应该选择其中一个,但不要两者兼而有之。

  2. 我建议您采用基于NSOperation的解决方案,因为您肯定希望(a)享受并发性;但是(b)将并发操作限制在一些合理的数字(比如4或5),否则你会有超时和失败的请求。

  3. 在获取文件名方面,您可以使用lastPathComponent中的NSURL检索文件名。 (我的下载操作,如果你没有提供明确的文件名,实际上会自动使用它。)

  4. 您尚未说明如何从远程服务器确定文件名列表,因此我们必须了解您如何知道要检索的图像。

  5. 如果这是出于您自己的目的,这很好,但我听说Apple拒绝通过蜂窝连接请求过多数据的应用程序(2000个图像肯定有资格)。坦率地说,即使Apple没有大惊小怪,在使用他们的大部分数据计划之前,你真的应该问用户。您可以使用Reachability来确定用户是通过wifi还是通过手机进行连接,如果是后者,您可能需要发出警告。

  6. 但我建议看起来像(假设您有NSArrayNSString版本的网址...显然会根据您的网址列表调整此格式:< / p>

    NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
    downloadQueue.maxConcurrentOperationCount = 4;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    
    for (NSString *urlString in urlStrings)
    {
        NSURL *url = [NSURL URLWithString:urlString];
        NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
        if (![fileManager fileExistsAtPath:path]) {
            DownloadOperation *downloadOperation = [[DownloadOperation alloc] initWithURL:url];
            downloadOperation.downloadCompletionBlock = ^(DownloadOperation *operation, BOOL success, NSError *error) {
                if (error) NSLog(@"download of %@ failed: %@", operation.url, error);
            };
            [downloadQueue addOperation:downloadOperation];
        }
    }
    

    该下载操作可能类似于this。显然,使用你想要的任何基于NSOperation的下载程序,但我建议你使用一个不会将整个下载加载到内存中的下载程序,而是将其直接流式传输到持久存储的程序。

    如果你不想那么喜欢,你可以这样做:

    NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
    downloadQueue.maxConcurrentOperationCount = 4;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    
    for (NSString *urlString in urlStrings)
    {
        NSURL *url = [NSURL URLWithString:urlString];
        NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
        if (![fileManager fileExistsAtPath:path]) {
            [downloadQueue addOperationWithBlock:^{
                NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
                NSData *data = [NSData dataWithContentsOfURL:url];
                if (data)
                    [data writeToFile:path atomically:YES];
            }];
        }
    }
    

    显然,使用您想要下载的任何下载操作类,但希望您能获得基本的想法。创建基于NSOperation的下载,然后为每个需要下载的文件提交一个。

答案 1 :(得分:1)

我不确定序列化信息的最佳方法(天真地,你可以将NSDictionary写入磁盘)。我会有一个大的NSDictionary(可以分解成更小的,直到你如何做到这一点)。 NSDictionary将采用图像名称“05052008321_bigger”并将其映射到简单的@YES。

当应用程序能够下载新图像时,它将从磁盘读取NSDictionary(可以在不同的线程中读取),并检查图像名称是否在字典中。这样可以快速查找。

- (BOOL)checkIfImageHasBeenDownloaded:(NSString *)imageName
{
    return [self.dictionaryNames objectForKey:imageName] != nil;
}