【问题标题】:Is creating UIImage thread safe?创建 UIImage 线程安全吗?
【发布时间】:2012-10-07 06:01:21
【问题描述】:

这样的调用是否被认为是线程安全的?它只是创建一个 UIImage,没有 UI 更新。我找不到任何关于此的文档。

UIImage * hiResImage = [[UIImage alloc] initWithContentsOfFile:path]; 

仅供参考,我稍后会像这样在主线程上进行 UI 更新...

[imageViewForZoom performSelectorOnMainThread:@selector(setImage:) withObject:hiResImage waitUntilDone:NO];

我已经知道的:

  • 从iOS4开始,UIKit的很多绘制方法都变成了线程安全的。阅读here
  • 我不应该在后台线程上更新 ui(例如,没有 [myImageView setImage:image];

编辑:让我们看看另一个观点。 “非线程安全”是否意味着它有可能永远被阻塞?或者只是意味着无法保证开始/持续时间的执行时间。如果是后一种情况,那么如果我们在加载图像时会有一些“不确定量”的延迟是没有问题的。 UI 更新在主线程上完成。因此,至少对于创建 UIImage 而言,它仍然被认为是非线程安全的。

我知道这与问题并没有真正的关系,但只是想指出这一点,因为我担心我的原始问题不会有明确的答案:)

【问题讨论】:

    标签: ios uiimage thread-safety


    【解决方案1】:

    我下面的经验不是直接用UIImage initContentsFromFile:而是用UIImage imageWithData,但是你的问题是关于UIImage线程安全的。

    我最近不得不调试使用从NSURLConnetionDelegate 函数connectionDidFinishLoading 调用的[UIImage imageWithData:] 使用多个后台线程下载图像的问题。由于下载的图像用于更新 UI,我不得不在下面使用[NSOperationQueue mainQueue] addOperationWithBlock ...

    - (void) connection:(URLConnection*)connection didReceiveData:(NSData *) data {
        [imgData appendData:data];
    }
    
    - (void) connectionDidFinishLoading:(NSURLConnection*)connection {
        [NSOperationQueue mainQueue] addOperationWithBlock:^{
            UIImage *img = [UIImage imageWithData:imgData];
            // more code here to update the UI
        }];
    }
    
    • 在 iOS 7.x 模拟器上运行时,img 持有有效图像
    • 在 iOS 7.x 设备 (iPod Touch) 上运行时,img 始终为 nil

    在调试会话期间,我注意到当调试器一次单步执行每个语句时,问题(暂时)消失了。我的理论是在调试器步进模式下运行不会让UIImage 处理运行imageWithData 的并发线程。因此,我认为UIImage imageWithData(可能还有其他类似的函数)不是线程安全的。

    使用@synchronized 块似乎可以解决问题

    - (void) connectionDidFinishLoading:(NSURLConnection*)connection {
        [NSOperationQueue mainQueue] addOperationWithBlock:^{
            @synchronized(imgData) {
                // Run the following in a synchronized block
                UIImage *img = [UIImage imageWithData:imgData];
            }
            // more code here ....
        }];
    }
    

    【讨论】:

      【解决方案2】:

      根据 Apple 的说法,答案是肯定的,从任何线程创建 UIImage 都是安全的:

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

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

      【讨论】:

        【解决方案3】:

        是的。在后台加载图像是相当普遍的做法,主要是在它是一个远程文件或者正在加载许多图像的情况下。是的,只在主线程上更新 UI。

        编辑:

        由于一些启发性的 cmets,我认为我会将我的第一个答案“是”修改为“根据经验和我对加载图像时 UIImage 线程安全性的可行替代方案的评估,我认为假设它是合理的。然而,每个人都有自己的观点,也许他或她与这里的代码故障相关的风险太高,无法在任何情况下做出假设。'

        【讨论】:

        • @Matt 问:创建 UIImage 线程安全吗? A:是的……——你有这方面的参考吗?
        • 此重复问题的评论中有文档:stackoverflow.com/questions/10645307/thread-safety-of-uiimage
        • @Matt 您链接的文档与 drawing UIImages 相关。但是,引用的文档对 creation 只字未提。就我而言,jfortmann 和 CodaFi 是值得关注的链接 QA 的贡献者。在幕后有很多图像——在保证发布之前,除了对象之外的东西不一定是线程安全的。当然,人们会这样做,但这并不意味着它受到支持——操作系统更新甚至多线程工作负载的差异(设备或工作负载差异)都有可能破坏执行此操作的程序。 (续)
        • (续)这实际上是一个非常好的问题,我认为适当的支持需要很长时间。你可能认为我是偏执狂,但我一直在使用其他方法在辅助线程上加载图像,因为(据我所知)这种保证从未存在过。
        • @Eiko 默认是 UIKit(和 AppKit)类型应该在主线程中使用,除非另有说明。
        猜你喜欢
        • 1970-01-01
        • 2020-09-28
        • 1970-01-01
        • 1970-01-01
        • 2012-02-17
        • 1970-01-01
        • 1970-01-01
        • 2017-04-29
        • 2020-04-15
        相关资源
        最近更新 更多