Как я могу загрузить изображения, не задерживая все остальное? - PullRequest
2 голосов
/ 03 марта 2010

Я создаю приложение, которое позволяет просматривать фотографии с веб-сайта. В настоящее время я загружаю изображения, используя:

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

, который прекрасно работает, но может занять много времени. Я начинаю с загрузки 20 изображений, но ничего не могу сделать, примерно через 30 секунд, чтобы загрузить их все.

Это однократное ожидание не так уж и плохо, но если я хочу загрузить 21-40-е изображения, мне придется подождать еще 30 секунд.

В принципе, есть ли способ загрузить эти изображения по одному, не задерживая анимацию?

Спасибо.

Ответы [ 3 ]

8 голосов
/ 03 марта 2010

Конечно, поместите задачу загрузки в поток и используйте обратный вызов, чтобы ваша программа знала, когда каждое изображение закончено. Затем вы можете нарисовать ваши изображения, как они заканчивают загрузку, а не задерживать остальную часть приложения. Эта ссылка содержит шаблон, который вы можете использовать в качестве примера.

Вот быстрый и грязный пример:

- (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 по завершении каждого.

3 голосов
/ 03 марта 2010

Хотя загрузка изображения в фоновом потоке, безусловно, является решением, я бы использовал NSOperation и NSOperationQueue вместо того, чтобы работать с потоками самостоятельно (это способ Apple Рекомендую заняться такими проблемами с потоками!)

NSOperationQueue будет иметь дело с хорошим запуском / остановкой потоков, и вы можете выбрать, сколько запускать одновременно и т. Д. Это в основном то же самое, что и другие ответы, но вы получаете немного больше контроля.

Здесь есть учебник , который выглядит довольно хорошо.

1 голос
/ 03 марта 2010

да, вы можете использовать вторичный поток и выполнять большую работу, или вы можете использовать вещи, которые нам дает яблоко.

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, которые обрабатывают или ошибку, или завершение. Вы также можете использовать объекты с автоматическим освобождением, но с точки зрения производительности мне нравится использовать их без объектов с автоматическим освобождением, когда я могу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...