如何在不耽误其他所有事情的情况下下载图像?

发布于 2024-08-23 17:55:31 字数 345 浏览 3 评论 0原文

我正在制作一个应用程序,允许您浏览网站上的图片。我目前正在使用以下方法下载图像:

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

效果很好,但可能很耗时。我一开始下载了 20 张图像,但直到 30 秒左右才能下载完所有图像,我什么也做不了。

这一次的等待还不算太糟糕,但如果我想下载第21-40张图像,我还得再等30秒。

基本上,有没有一种方法可以一次下载这些图像而不中断任何动画?

谢谢。

I'm making an app that allows you to browse through pictures from a website. I'm currently downloading the images using:

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

which works great, but can be time consuming. I start off by downloading 20 images, but I can't do anything until after the 30 or so seconds it takes to download them all.

This one time wait isn't all that bad, but if I want to download the 21st-40th images, I would have to wait another 30 seconds.

Basically, is there a way I can download these images one at a time without holding up any of my animations?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蹲墙角沉默 2024-08-30 17:55:31

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

这是一个快速而肮脏的示例:

- (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

Sure, put the download task in a thread, and use a callback to let your program know when each image is finished. Then you can draw your images as they finish loading, and not hold up the rest of the app. This link has a template that you can use as an example.

Here's a quick and dirty example:

- (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
}

Call downloadImageOnThread for every image you want to load, each will get its own thread, and you'll get calls to imageLoaded as each one completes.

凉风有信 2024-08-30 17:55:31

虽然在后台线程上加载图像绝对是解决方案,但我会使用 NSOperationNSOperationQueue 而不是自己处理线程(这是 Apple 建议处理此类线程问题的方式!)

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

教程看起来很不错。

While loading the image on a background thread is definately the solution, I'd use an NSOperation and an NSOperationQueue instead of dealing with the threads yourself (this is the way Apple recommend to deal with threading problems like this!)

The NSOperationQueue will deal with starting/stopping the threads nicely and you can choose how many to run at once etc. It's basically a the same as the other answers but you get a little more control.

There's a tutorial here that looks pretty good.

微暖i 2024-08-30 17:55:31

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

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");
}

代码有点难看,但是更改它并不难,因为您获得了所需的 3 个内容,即开始下载的方法和 2 个处理错误或完成的方法。
您还可以更多地使用自动释放的对象,但就性能而言,我喜欢尽可能使用不使用自动释放的对象。

yeah you can use a secondary thread, and do a lot of work OR you could use things that apple gives us.

NSURLDownload, doesn't "lag" your main thread, You spawn it with a method and you set a endSelector, the endSelector will get called when the download is done.
Spawning a secondary thread for this is not really what you should do.

here you got some code from my app wich does it work perfectly without giving a beach ball of doom.

- (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");
}

The code is a bit ugly, but its not hard to change it as you got the 3 things you need, the method that starts the download and 2 that handle or an error or the finish.
You can also use autoreleased objects some more, but in terms of performance I like using it without autoreleased objects when I can.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文