Как лучше всего выполнять несколько задач в блоках и очередях iOS? - PullRequest
4 голосов
/ 08 ноября 2011

Я начал интенсивно использовать блоки и очереди, и они были великолепны.Я использую гораздо меньше кода, и его гораздо проще создавать и поддерживать.Но меня интересует производительность.В одном случае я показываю экран, полный миниатюрных изображений из набора фотографий Flickr.Код перебирает все элементы и запускает уникальную очередь загрузки для одновременной загрузки каждой фотографии.Он работает просто отлично, но мне интересно, стоит ли мне вместо этого создать единую статическую очередь для загрузки фотографий, а затем отправить эти блоки загрузки в ту же очередь, чтобы она могла эффективно управлять блоками.

Я загрузилпример здесь.

http://www.smallsharptools.com/Downloads/iOS/UIImage+DownloadImage.zip

Содержание реализации также приведено ниже.Я ценю любую информацию о лучшей производительности.(Позже я хотел бы заняться кэшированием изображений, поместив файл в папку tmp, чтобы они периодически периодически очищались.)

Как вы управляете параллельными задачами с блоками?Вы создаете статическую очередь и отправляете блоки в общую очередь?Или реализация ниже неявно управляет всеми моими задачами уже эффективно?

#import "UIImage+DownloadImage.h"

@implementation UIImage (DownloadImage)

+ (void)downloadImageWithURL:(NSURL *)imageURL andBlock:(void (^)(UIImage *image, NSError *error))returnImage {

    dispatch_queue_t callerQueue = dispatch_get_current_queue();
    dispatch_queue_t downloadQueue = dispatch_queue_create("Image Download Queue", NULL);
    dispatch_async(downloadQueue, ^{
        UIImage *image = nil;
        NSError *error = nil;

        // use the default cache policy to do the memory/disk caching
        NSMutableURLRequest *request = [NSMutableURLRequest 
                                        requestWithURL:imageURL 
                                        cachePolicy:NSURLRequestUseProtocolCachePolicy 
                                        timeoutInterval:15];

        NSHTTPURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        // 200 indicates HTTP success
        if (response.statusCode != 200) {
            data = nil;

            // set the error to indicate the request failed
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithFormat:@"Request failed with HTTP status code of %i", response.statusCode], NSLocalizedDescriptionKey, nil];
            error = [NSError errorWithDomain:@"UIImage+DownloadImage" code:response.statusCode userInfo:userInfo];
        }
        else if (!error && data) {
            image = [UIImage imageWithData:data];
        }

        // image will be nil if the request failed

        dispatch_async(callerQueue, ^{
            returnImage(image, error);
        });
    });
    dispatch_release(downloadQueue);
}

@end

Ответы [ 2 ]

4 голосов
/ 09 ноября 2011

Кажется неэффективным каждый раз создавать 1-элементную очередь, хотя я был бы удивлен, если бы это проявилось как горячая точка во время профилирования.

Если вы будете искать на форумах Apple по iOS, вы сможете найти обсуждение Куинном вопроса об использовании NSURLConnection "raw", а не через потоки.

1 голос
/ 09 ноября 2011

Вы выполняете синхронную сетевую активность в очередях.Это кажется довольно плохой идеей, поскольку вы блокируете потоки и заставляете GCD запускать новые потоки для обслуживания других блоков.Если вы одновременно загружаете 20 изображений, в вашем приложении будет 20 заблокированных тем и еще одна кучка, которая действительно будет работать.Вместо этого вы должны выполнять асинхронную сетевую активность в одном рабочем потоке.Есть даже пример кода Apple, который делает это, хотя я не могу вспомнить, как он называется.

...