在iOS块和队列中运行多个任务的最佳实践是什么?

时间:2011-11-08 16:05:24

标签: ios performance cocoa-touch objective-c-blocks grand-central-dispatch

我已经开始大量使用块和队列了,而且它们很棒。我使用的代码少得多,而且构建和维护也更容易。但我想知道表现。在一个案例中,我正在显示一个充满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 个答案:

答案 0 :(得分:4)

每次创建1个元素的队列似乎效率低下,但如果在分析期间这会显示为热点,我会感到惊讶。

如果您在Apple的iOS论坛上搜索,您应该能够找到Quinn关于使用NSURLConnection“raw”而不是通过线程的讨论。

答案 1 :(得分:1)

您正在对队列进行同步网络活动。这似乎是一个相当糟糕的想法,因为你阻止线程并强制GCD启动新线程来服务其他块。如果您同时下载了20个图像,那么您的应用程序中将有20个被阻止的线程,而另一个用于实际工作。相反,您应该在单个工作线程上执行异步网络活动。甚至有一段Apple样本代码可以做到这一点,虽然我不能为我的生活记住它的名字。