4

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

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

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

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

我已经知道的:

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

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

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

4

3 回答 3

4

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

我最近不得不调试一个使用从函数[UIImage imageWithData:]调用的问题,以使用多个后台线程下载图像。由于下载的图像用于更新 UI,因此我必须使用以下内容:NSURLConnetionDelegateconnectionDidFinishLoading[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 ....
    }];
}
于 2013-10-20T02:29:27.187 回答
2

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

由于图像对象是不可变的,因此您无法在创建后更改它们的属性。大多数图像属性是使用随附图像文件或图像数据中的元数据自动设置的。图像对象的不可变特性也意味着它们可以安全地从任何线程创建和使用

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

于 2017-03-21T06:26:21.477 回答
1

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

编辑:

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

于 2012-10-07T06:15:13.903 回答