2010-03-03 51 views
2

我正在制作一个应用程序,允许您浏览网站上的图片。我目前正在使用下载图像:如何在不阻碍其他情况下下载图像?

UIImage *myImage = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]]; 

它工作很好,但可能很费时。我从下载20张图像开始,但在完成下载所需的30秒后,我无法做任何事情。

这一次等待并不是那么糟糕,但如果我想下载第21 - 40张图像,我将不得不再等待30秒。

基本上,有没有一种方法可以一次下载这些图像,而不会阻止我的任何动画?

谢谢。

回答

8

当然,将下载任务放在一个线程中,并使用回调让程序知道每个图像何时完成。然后,您可以在完成加载时绘制图像,而不会妨碍应用程序的其余部分。 This link有一个您可以用作示例的模板。

这里有一个快速和肮脏的例子:

- (void)downloadWorker:(NSString *)urlString 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSURL    *url = [NSURL URLWithString:urlString]; 
    NSData   *data = [NSData dataWithContentsOfURL:url]; 
    UIImage   *image = [[UIImage alloc] initWithData:data]; 

    [self performSelectorOnMainThread:@selector(imageLoaded:) 
          withObject:image 
         waitUntilDone:YES]; 
    [image release]; 
    [pool drain]; 
} 

- (void)downloadImageOnThread:(NSString *)url 
{ 
    [NSThread detachNewThreadSelector:@selector(downloadWorker:) 
          toTarget:self 
          withObject:url]; 
} 

- (void)imageLoaded:(UIImage *)image 
{ 
    // get the image into the UI 
} 

电话downloadImageOnThread为要加载,每次都会得到自己的线程每一个形象,并作为每一个完成,你会得到调用imageLoaded

+0

对不起,但我不确定你是什么意思或我该怎么做。你能再解释一下吗? – androidnotgenius 2010-03-03 04:24:39

+0

@pureman,你看到链接了吗?这非常简单 - 您使用'[NSThread detachNewThreadSelector ...]'创建一个具有特定方法的线程,然后在worker线程完成时使用'performSelectorOnMainThread'回调应用程序。 – 2010-03-03 04:32:59

+0

我会在我的答案中添加一些代码以清除它。 – 2010-03-03 04:34:51

1

是的,你可以使用辅助线程,并做了很多工作,或者你可以使用苹果给我们的东西。

NSURLDownload不会“滞后”你的主线程,你用方法产生它并设置一个endSelector,endSelector将在下载完成时被调用。 产生这样的辅助线程并不是你真正应该做的。

这里你从我的应用程序得到了一些代码,它完美的工作,没有给予厄运的沙滩球。

- (void)downloadAvatar:(NSString *)URL{ 
NSURL *url = [[NSURL alloc] initWithString:URL]; 
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 
[url release]; 
NSURLDownload *download = [[NSURLDownload alloc] initWithRequest:request delegate:self]; 
NSString *path = [[NSString alloc] initWithFormat:@"%@data/%@.jpg",[[BFAppSupport defaultSupport] bfFolderPath],[[xfSession loginIdentity] userName]]; 
[download setDestination:path allowOverwrite:YES]; 
[download release]; 
[path release]; 
[request release]; 
} 
- (void)downloadDidFinish:(NSURLDownload *)download{ 
NSString *path = [[NSString alloc] initWithFormat:@"%@data/%@.jpg",[[BFAppSupport defaultSupport] bfFolderPath],[[xfSession loginIdentity] userName]]; 
NSData *imageData = [[NSData alloc] initWithContentsOfFile:path]; 
if([imageData length] < 10){ 
    [self performSelector:@selector(downloadAvatar:) withObject:@"http://media.xfire.com/xfire/xf/images/avatars/gallery/default/xfire160.jpg" afterDelay:0.0]; 
    [imageData release]; 
    [path release]; 
    return; 
} 
NSImage *theImage = [[NSImage alloc] initWithData:imageData]; 
[imageData release]; 
[path release]; 
[yourImage setImage:theImage]; 
[theImage release]; 
} 

- (void)download:(NSURLDownload *)aDownload didFailWithError:(NSError *)error{ 
NSLog(@"Avatar url download failed"); 
} 

的代码是丑了一点,但它不是很难改变它,你得到了你所需要的三两件事,即开始下载和2处理或错误,或完成的方法。 您还可以使用更多的自动释放对象,但就性能而言,我喜欢在不使用自动释放对象的情况下使用它。

3

虽然在后台线程加载图像是肯定的解决方案,我会使用和处理的线程的NSOperationNSOperationQueue,而不是你自己(这是苹果推荐对付这样的线程问题的方式!)

NSOperationQueue将很好地处理启动/停止线程,您可以选择一次运行多少个等等。它基本上与其他答案相同,但您可以获得更多的控制权。

有一个tutorial here,看起来不错。

相关问题