Load an image from an asset catalog off the main thread?

时间:2015-07-31 20:26:23

标签: ios uiimage assets

I'm trying to load an image from an asset catalog into a UIImage off of the main thread, but can't seem to find any way to do it. If the image was not in an asset catalog I would use pathForResource and imageWithContentsOfFile:

NSString *path = [[NSBundle mainBundle] pathForResource:icon ofType:nil];
if(path) {
  image = [UIImage imageWithContentsOfFile:path];
}

But pathForResource: does not work for images in asset catalogs. Is there any way to do this without having to go to the main thread to load the image? Im guessing the answer is no.

What won't work:

  • Manually creating the path for the image based on the main bundle path. I have images in multiple asset catalogs, and asset catalogs can be compiled in a binary form.
  • [UIImage imageNamed:] is not thread safe, and can not be used off the main thread. The docs have said it's not thread safe for at least the last several major releases of iOS, and starting in iOS 8 it really does crash when used off the main thread.

What i'm doing now:

dispatch_sync(dispatch_get_main_queue(), ^{
  image = [UIImage imageNamed:icon];
});

2 个答案:

答案 0 :(得分:2)

您似乎已经回答了自己的问题:使用dispatch_sync在主线程上调用imageNamed:

资产目录格式不透明;您唯一的界面是imageNamed:。它的文件说:

  

此方法在系统缓存中查找具有指定名称的图像对象,并返回该对象(如果存在)。如果匹配的图像对象尚未存在于缓存中,则此方法将从磁盘或资产目录中查找并加载图像数据,然后返回结果对象。你不能假设这个方法是线程安全的。

速度和安全之间需要权衡; Apple选择了速度。要允许从任何线程调用imageNamed:,需要(A)同步对系统缓存的访问,增加开销或(B)根本不使用缓存。

由于imageNamed:最常用于支持UI的图像加载,并且UI工作已经与主线程相关联,因此围绕该情况进行优化并推动同步工作是有意义的不在主线程上的来电者。

因此,使用dispatch_sync是可行的方法。如果您担心线程争用,您可以轻松地缓存图像,以便后台线程只在必要时才在主线程上等待。我不会这样做,除非你通过剖析确定它会在性能上产生明显的差异。

请注意,如果Apple决定允许在后台线程上调用imageNamed:,那么他们必须同步对其缓存的访问权限,使得 的性能不同于将dispatch_sync添加到您自己的代码中。

如果您的要求是:

  • 你必须绝对,积极地,永远不要触及主线;和
  • 您必须绝对,积极地将您的图片包含在资产目录中;

然后我能看到的唯一选择是反向设计资产目录文件格式并直接从磁盘读取。如果文件格式发生变化,您的应用可能会中断,但幸运的是,这只会在构建时发生,因此未来的操作系统更新不应该破坏您的应用。

答案 1 :(得分:-1)

如果您正在加载项目中保存的图片,请使用[UIImage imageNamed: @"image1"];无@!#34; image1.png"

等扩展程序
UIImage *image = [UIImage imageNamed: @"<#image name#>"];

希望这会有所帮助:)