1

嗨,我正在学习斯坦福 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 并处理调用方法中的所有线程?

谢谢

4

2 回答 2

2

你的代码不会做你想做的事。

您将一个异步块放入队列中,然后立即从该方法返回。您不能保证该块在您返回之前会实际运行——事实上,它很可能不会运行。

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

__block UIImage *image = nil;

那会更有礼貌一点。

这里的问题是:您的方法必须返回 a UIImage,因此在返回之前您必须等待完全构造 a 所需的时间UIImage。在其他线程上执行此操作的好处为零——您仍在等待相同的时间,并且切换线程只会增加开销。

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

于 2012-04-09T05:22:27.333 回答
0

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

于 2012-04-09T04:43:12.090 回答