在后台线程中加载UIImage

4

在不引起线程问题的情况下,是否可以在后台线程中加载UIImage?如果不行,有什么最好的方法吗?我正在使用iOS 8。以下是我目前的做法:

    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(backgroundQueue, ^{
        UIImage *image = [UIImage imageNamed: fileName];

        // only update UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            [self setImage: image];
        });

    });

你当前的示例有什么问题? - Coldsteel48
我曾在后台加载图片时遇到CG ImageIO错误,所以我想知道为什么会出现这种情况。这里的人说,你不应该在后台加载UIImages,那样就能解决问题了。 - Max
也许 imageWithContextOfURl 可以帮助你,只需将 url 替换为你的 nsbundle 路径即可。https://dev59.com/I2445IYBdhLWcg3wQX-G - Coldsteel48
1个回答

14
你所做的工作在结构上是可行的,但我不知道imageNamed:是否线程安全 - 我没有理由认为它是安全的。除非文档另有说明,否则应始终假定事物是不安全的。在这种情况下,文档明确说明它是不安全的

您不能假定此方法是线程安全的。

在我看来,你应该问一下自己是否真的需要这样做。imageNamed:包括一个缓存机制,应该可以解决你所担心的任何问题。无论如何,过早地进行优化只是浪费你的时间和精力。这里真的存在问题吗?使用Instruments找出;不要使用直觉或本能。

如果问题是你的图像太大,并且选择了糟糕的格式 - 例如,你正在使用非常大的JPEGs - 那么最好集中精力纠正那个

编辑 iOS 9文档现在说:“在iOS 9及更高版本中,此方法是线程安全的。”这表明我的答案是正确的,问题现在已经解决。


1
感谢您的快速回复。我知道使用imageNamed会有缓存,但是第一次加载仍然需要时间。我正在加载背景图像,这些图像很大,我希望在它们完成加载后立即呈现给用户,以便用户看不到任何延迟。 - Max
5
我所看到的是,-[UIImage imageNamed:] 曾经是线程安全的... 直到 iOS 8。从那时起,在后台线程调用它会导致许多崩溃,而我们多年来一直这样做而没有问题。 - DarkDust
1
@DarkDust非常有用的信息,感谢您添加。人们可能会挑剔并说imageNamed:可能实际上并不是线程安全的 - 除非我们明确被告知它是线程安全的,否则没有什么是线程安全的 - 但是您的经验表明,您以前可以在后台使用它(即使您可能不应该这样做),现在您不能,这肯定是有趣的。 - matt
1
@DarkDust文档明确指出imageNamed:方法“不能假定该方法是线程安全的。”因此,如果您一直在这样做,那么您一直都是在错误地使用它。 - matt
2
一年多后的补充说明:苹果已经更新了文档,明确说明[UIImage imageNamed:]在iOS 9及更高版本中是线程安全的。这真是个好消息。https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/#//apple_ref/occ/clm/UIImage/imageNamed: - Peter E
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接