我想将大量(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.检查图像是否已下载,请勿再次下载。
我知道,也许这不仅仅是一个问题。但是一些建议,指示会非常好。
提前致谢。
答案 0 :(得分:2)
一些反应:
您正在发起NSURLConnection
connectionWithRequest
(触发NSURLConnectionDataDelegate
方法),但您显然忽略了这一点并发起了dataWithContentsOfURL
。你应该选择其中一个,但不要两者兼而有之。
我建议您采用基于NSOperation
的解决方案,因为您肯定希望(a)享受并发性;但是(b)将并发操作限制在一些合理的数字(比如4或5),否则你会有超时和失败的请求。
在获取文件名方面,您可以使用lastPathComponent
中的NSURL
检索文件名。 (我的下载操作,如果你没有提供明确的文件名,实际上会自动使用它。)
您尚未说明如何从远程服务器确定文件名列表,因此我们必须了解您如何知道要检索的图像。
如果这是出于您自己的目的,这很好,但我听说Apple拒绝通过蜂窝连接请求过多数据的应用程序(2000个图像肯定有资格)。坦率地说,即使Apple没有大惊小怪,在使用他们的大部分数据计划之前,你真的应该问用户。您可以使用Reachability来确定用户是通过wifi还是通过手机进行连接,如果是后者,您可能需要发出警告。
但我建议看起来像(假设您有NSArray
个NSString
版本的网址...显然会根据您的网址列表调整此格式:< / 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;
}