UIImage的线程安全

Posted

技术标签:

【中文标题】UIImage的线程安全【英文标题】:Thread safety of UIImage 【发布时间】:2012-05-18 00:38:32 【问题描述】:

我知道苹果官方推荐 UIKit 只在主线程中使用。但是,我也听说 UIImage 自 ios 4.0 以来是线程安全的。我找不到任何支持这一说法的文件。

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

【问题讨论】:

顺便说一句,这是一个始终检查 UIKit 内主线程访问的警卫:gist.github.com/steipete/5664345 【参考方案1】:

直接来自Apple's documentation for UIImage

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

(强调我的)

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

【讨论】:

这才是真正的答案 “使用”,包括制作吗? (初始化程序) 我认为是这样,但我鼓励您验证这一点。 @Eonil -- 看起来可能有一些警告,正如 AFNetworking 项目在使用 imageWithData: 从不同线程初始化许多 UIImage 时发现的那样。见这里:github.com/AFNetworking/AFNetworking/pull/2860 @EricGoldberg 我只是禁止从多线程调用 UIImage 初始化程序,现在我得到了更多线索。谢谢。【参考方案2】:

苹果确实推荐在主线程上使用 UIKIt 中的元素:

注意:在大多数情况下,UIKit 类只能从 应用程序的主线程。对于类来说尤其如此 派生自 UIResponder 或涉及操纵您的 应用程序的用户界面。

由于 UIImage 不是从 UIResponder 派生的,因此您实际上不会在界面/屏幕上显示它。那么在另一个线程上对 UIImages 进行操作应该是安全的。

不过,这是基于我的经验,我还没有看到任何关于它的官方文档。

【讨论】:

在 CGImage 上操作要安全得多,仅供参考。 嗯,是的,但是在两者之间转换很容易,所以不是很离题。 Stuff 要么是线程安全的,要么不是。 CGImage 并不比 UIImage 或多或少是线程安全的。 UIImage 的任何线程安全保证上面也没有引用摘录。它强烈建议不要摆弄 UIResponder 派生类,但对 UIImage 只字未提。不要仅仅因为它不是 UIResponder 就认为它是安全的。另一方面,What's new for iOS 4 文档提到,从 4.0 开始,绘制 UIImage 和在 UIImage 上绘制是线程安全的。所以抽离吧! 我想接受 jfortmann 的评论。这正是我正在寻找的。​​span> 【参考方案3】:

自从此处发布较早的答案以来,Apple 似乎已经更新了他们的文档。根据最新的文档,从任何线程创建和使用 UIImage 实例都是安全的:

因为图像对象是不可变的,你不能改变它们 创建后的属性。大多数图像属性是自动设置的 使用随附图像文件或图像数据中的元数据。这 图像对象的不可变特性也意味着它们是安全的 从任何线程创建和使用

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

【讨论】:

这是目前最简单正确的答案,谢谢@Arda。【参考方案4】:

在What's New in iOS: iOS 4.0 发行说明中,UIKit 框架增强功能包括以下内容:

在 UIKit 中绘制到图形上下文现在是线程安全的。 具体来说:用于访问和操作图形的例程 上下文现在可以正确处理驻留在不同的上下文 线程。字符串和图像绘制现在是线程安全的。使用颜色和 现在可以安全地在多个线程中使用字体对象。

所以 UIImage 在 iOS 4.0 及更高版本上是线程安全的。

【讨论】:

该声明并不意味着 UIImage 在任何方面都是安全的。它只是说在上下文中绘制图像是线程安全的。【参考方案5】:

简而言之: UIImage 不是线程安全的,或者更好的是只在主线程上工作, 正如我在调试后所经历的那样。

我希望这会有所帮助。 我希望苹果能更清楚地说明这一点 甚至更好的 UIImage 类,它可以在不同的线程中呈现。 应该不会太难...

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

感谢 Zachary Waldowski。

【讨论】:

不再正确(参见 Eric Goldberg 的回答) UIImage 一直是不可变的类;它引用的图像不能被改变。这使它 100% 线程安全。【参考方案6】:

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

当将 Core Image 过滤器与 vImage 操作混合时会发生这种情况。两者都是线程安全的,但 ARC 不会在处理 Core Image 对象之前释放 vImage 缓冲区数据,因此您有时会在内存中拥有两个图像副本。

因此,如果不了解线程和并发性,您永远不会认为您对线程安全的了解是完整的——这对于任何有关线程安全的问题的回答都是加倍的。简而言之:正确的问题是,当您谈论图像处理时,线程安全如何应用于内存使用。

如果您只是在此试探,则需要等到遇到真正的问题后再提出问题。但是,如果您正在计划下一步行动,您需要知道如何按顺序执行图像处理命令,并使用手动解除分配。您必须设计您的应用程序,以便在内存中只有一个正在处理的图像副本。永远不要依赖自动释放(线程安全与否)来为您进行调用。它不会工作。

【讨论】:

如果您要否决有效的答案,请让 grumba 说出原因。在斗篷后面狙击只值得一听!

以上是关于UIImage的线程安全的主要内容,如果未能解决你的问题,请参考以下文章

Java线程安全和非线程安全

如何创建线程?如何保证线程安全?

如何创建线程?如何保证线程安全?

如何保证线程安全?

如何确保Java线程安全?

如何创建线程?如何保证线程安全?