UIImage的线程安全性

7

我知道苹果公司官方推荐仅在主线程中使用UIKit。然而,我也听说自iOS 4.0起,UIImage是线程安全的。但我找不到任何支持这一说法的文档。

有没有人有相关信息来支持这一说法?作为用于存储数据和解码图像数据的类,如果设计得当,UIImage应该是线程安全的。


顺便提一下,这里有一个在UIKit中始终检查主线程访问的保护程序:https://gist.github.com/steipete/5664345 - steipete
6个回答

29

直接引用来自苹果的UIImage文档

图像对象是不可变的,因此在创建后无法更改其属性。这意味着通常在初始化时指定图像的属性或依靠图像的元数据提供属性值。这也意味着图像对象本身可以从任何线程安全使用。 要更改现有图像对象的属性,请使用其中一个可用的方便方法来创建图像的副本,但带有您想要的自定义值。

(强调是我加的)

因此,至少在2014年5月13日的SDK的当前版本中,“图像对象本身可以从任何线程安全使用”。


3
这是真正的答案。 - jlukanta
“使用”这个词是否包括创建它们?(初始化器) - eonil
我认为是这样,但我鼓励你去验证一下。 - Eric G
1
@Eonil -- 看起来可能存在一些注意事项,就像AFNetworking项目在使用imageWithData:从不同的线程初始化许多UIImages时发现的那样。请参见此处:https://github.com/AFNetworking/AFNetworking/pull/2860 - Eric G
1
@EricGoldberg,我刚刚禁止从多个线程调用UIImage初始化程序,现在我又得到了一个线索。谢谢。 - eonil
我也遇到了初始化问题,因此我创建了一个单独的线程来解决这个问题: https://dev59.com/hJzha4cB1Zd3GeqPGozY - fancy

5

苹果公司确实建议在主线程上使用UIKIt中的元素:

注意:在大多数情况下,UIKit类应该只从应用程序的主线程使用。特别是那些派生自UIResponder或涉及以任何方式操作应用程序用户界面的类。

由于UIImage没有派生自UIResponder,并且您实际上没有在界面/屏幕上显示它。因此,在另一个线程上使用UIImages进行操作应该是安全的。

但是,这是基于我的经验,我没有看到任何官方文档支持这一点。


1
顺便提一下,使用CGImage操作更安全。 - CodaFi
啊,是的,但在两者之间进行转换非常容易,所以这并不完全是离题。 - CodaFi
21
东西要么是线程安全的,要么不是。CGImage并不比UIImage更或者不如线程安全。上面引用的摘录也不能保证UIImage的线程安全性。它强烈建议不要去操作UIResponder派生类,但是对于UIImage则没有任何相关提及。不要因为UIImage不是UIResponder而盲目认为它是安全的。另一方面,《iOS 4新特性》文档提到从4.0版本开始,绘制UIImages和在UIImages上进行绘制都是线程安全的。所以,放心地画吧! - jfortmann
我想接受jfortmann的评论。那正是我要找的。 - Evil Nodoer

4
看起来苹果公司已更新了他们的文档,自早期的回答发布以来。根据最新的文档,安全地从任何线程创建和使用UIImage实例是可行的:
因为图像对象是不可变的,所以在创建后不能更改它们的属性。大多数图像属性会使用附带图像文件或图像数据中的元数据自动设置。图像对象的不可变性也意味着它们可以从任何线程 安全地创建和使用

https://developer.apple.com/reference/uikit/uiimage


这是目前更简单和正确的答案,感谢@Arda。 - Ricardo Barroso

2
在iOS 4.0的发布说明中,UIKit框架增强包括以下内容:
绘制UIKit中的图形上下文现在是线程安全的。具体来说:用于访问和操作图形上下文的例程现在可以正确地处理驻留在不同线程上的上下文。字符串和图像绘制现在是线程安全的。在多个线程中使用颜色和字体对象现在也是安全的。
因此,在iOS 4.0及更高版本中,UIImage是线程安全的。

1
该语句并不意味着UIImage在任何情况下都是安全的。它只是说在上下文中绘制图像是线程安全的。 - Anurag

1

简单来说: UIImage不是线程安全的,或者更好地说,只能在主线程上工作, 我在当前的调试中经历过这种情况。

我希望这可以帮助您。 我希望从苹果公司获得更多关于此事的明确性, 甚至最好是一个UIImage类,可以在不同的线程中呈现。 这应该不太困难...

编辑: 经过一些研究,我发现是“UIGraphicsGetImageFromCurrentImageContext();” 引起了麻烦。 这有点偏题,但也许这有所帮助: https://coderwall.com/p/9j5dca

感谢Zachary Waldowski。


不再正确(请参见Eric Goldberg的答案) - jlukanta
UIImage是一个不可变类,它引用的图像是不可变的。这使得它100%线程安全。 - James Bush

-1

线程安全不是问题,因为任何线程都可以同时(并发)尝试访问上下文。虽然这通常没问题,但在低内存情况下,例如在iOS设备上的照片编辑扩展中,两个线程访问一个上下文可能会由于内存不足而导致应用程序崩溃。

当混合使用Core Image滤镜和vImage操作时会出现这种情况。两者都是线程安全的,但ARC在处理Core Image对象之前不会释放vImage缓冲区数据,因此在内存中会有两份图像副本。

因此,在谈论图像处理时,您永远不应认为自己对线程安全的了解已经完整,除非您理解了线程和并发性——这对于任何关于线程安全的问题都是如此重要。简而言之:正确的问题是,无论何时谈论内存使用情况,线程安全如何应用于图像处理。

如果您只是在试水,请等到遇到真正的问题再提出您的问题。但是,如果您正在计划下一步行动,您需要知道如何按顺序执行图像处理命令,并进行手动释放。您必须设计您的应用程序,以便在内存中只有一个图像副本被处理。永远不要依赖自动释放——无论是否线程安全——来为您做出决定。这是行不通的。


1
如果你要对一个可行的答案进行负评,请有勇气说出原因。在幕后暗箭伤人只会让你变得不堪一击! - James Bush

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