在iOS中使用线程返回图像

时间:2012-04-09 03:42:52

标签: ios multithreading uikit

您好我正在通过斯坦福iOS开发课程。我有一个关于线程的问题。我理解UIKit调用应该由主线程处理。我想知道这样的事情是否合法?

- (UIImage *)mapViewController:(MapViewController *)sender imageForAnnotation:(id<MKAnnotation>)annotation {
    FlickrPhotoAnnotation *fpa = (FlickrPhotoAnnotation *) annotation;
    NSURL *url = [FlickrFetcher urlForPhoto:fpa.photo format:FlickrPhotoFormatSquare];

    __block UIImage *image;
    dispatch_queue_t downloadQ = dispatch_queue_create("download queue", NULL);
    dispatch_async(downloadQ, ^{
        NSData *data = [NSData dataWithContentsOfURL:url];
        if (data) {
            dispatch_async(dispatch_get_main_queue(), ^{
                image = [UIImage imageWithData:data];
            });
        }
    });
    dispatch_release(downloadQ);
    return image;
}

或者我应该只返回NSData并处理调用方法中的所有线程?

由于

2 个答案:

答案 0 :(得分:2)

您的代码无法执行您想要的操作。

您正在将异步块放入队列,然后立即从该方法返回。你无法保证在返回之前该块实际上会运行 - 实际上,可能性不大。

因此,您将返回image的当前值。由于你没有初始化它,它可能是垃圾。调用此方法的人将尝试使用垃圾指针指向图像,并且(如果幸运的话)会崩溃。如果您已将其初始化为nil:

__block UIImage *image = nil;

会更有礼貌。

问题在于:您的方法必须返回UIImage,因此您必须等待返回之前完成UIImage完整构建所需的时间。在其他一些线程上执行此操作没有任何好处 - 您仍在等待相同的时间,并且切换线程只会增加开销。

为了以有用的异步方式加载图像,您需要某种方法通过回调委托方法或块来异步告知调用者何时加载图像。例如,查看Foundation中的NSURLConnection。它有一个通过委托回调的旧方法,以及通过块回调的新方法(+sendAsynchronousRequest:queue:completionHandler:)。

答案 1 :(得分:0)

我同意CodaFi的评论。实际上,可以在主线程之外创建图像。 UIView的创建和操作必须在主线程上完成,但UIImage不是UIView。此外,如果您尝试在另一个线程上操作显示UI,则运行时可能会给您一个警告或错误(当我意外地在另一个线程上更新UITableView时,它为我做了)。