使用Apple ODR下载的图片无法显示,如何正确加载?
ODR资源加载问题
我在Xcode的资源标签中为一组图片添加了"cat-images"标签,测试时执行以下代码成功获取资源:
let resourceRequest = NSBundleResourceRequest(tags: Set(["cat-images"])) resourceRequest.conditionallyBeginAccessingResources { (resourcesAvailable) in if resourcesAvailable { completion(nil) } else { resourceRequest.beginAccessingResources { (error) in completion(error) } } }
但尝试显示其中一张图片时,使用UIImage(named: "siamese.png").map { Image(uiImage: $0) }及自定义的加载方法:
extension Image { static func loadFromODR(resourceName: String) -> Image? { let components = resourceName.split(separator: ".") let name = String(components[0]) let ext = String(components[1]) print("attempting odr image: \(name).\(ext)") guard let path = Bundle.main.path(forResource: name, ofType: ext), let image = UIImage(contentsOfFile: path) else { print("could not find: \(name).\(ext)") return nil } return Image(uiImage: image) } }
均无法找到图片。请问ODR资源是否需要特殊的加载方式?是否每个图片都需要单独设置ODR标签?
问题解答
不需要为每个图片单独设置ODR标签,用组标签"cat-images"批量关联资源的方式完全可行。
ODR资源加载的关键修正点:
- 移除文件名扩展名:使用
UIImage(named:)时不要带.png后缀,正确写法是UIImage(named: "siamese")——该方法会自动匹配对应格式的资源,带扩展名反而会导致资源匹配失败。 - 确保异步回调后再加载:
beginAccessingResources是异步操作,必须在其回调确认资源可用后,再执行图片加载逻辑。如果后续加载逻辑没等待回调完成,会出现资源未下载就查找的情况。 - 检查资源配置:
- 确认图片的
Resource Tags确实关联到"cat-images",且Target Membership勾选了当前运行的Target; - 在项目Target的
General页面,确认On Demand Resources已启用,对应标签的资源被正确包含; - 优先用真机测试:模拟器会直接使用本地资源,无法复现真实ODR下载流程,容易排查错误。
- 确认图片的
- 移除文件名扩展名:使用
修正后的加载示例:
let resourceRequest = NSBundleResourceRequest(tags: Set(["cat-images"])) resourceRequest.conditionallyBeginAccessingResources { [weak self] resourcesAvailable in if resourcesAvailable { self?.displayCatImage() } else { resourceRequest.beginAccessingResources { error in guard error == nil else { print("ODR资源下载失败: \(error!)") return } self?.displayCatImage() } } } func displayCatImage() { // 正确加载方式:不带扩展名 if let uiImage = UIImage(named: "siamese") { let image = Image(uiImage: uiImage) // 这里更新UI显示图片 } else { print("无法找到siamese图片") } }
- 自定义加载方法的优化:如果必须用
contentsOfFile加载,要注意资源名含多个.的情况(比如siamese.v1.png),原拆分逻辑会出错,可改用URL拆分扩展名:
extension Image { static func loadFromODR(resourceName: String) -> Image? { let url = URL(fileURLWithPath: resourceName) let name = url.deletingPathExtension().lastPathComponent let ext = url.pathExtension print("attempting odr image: \(name).\(ext)") guard let path = Bundle.main.path(forResource: name, ofType: ext), let image = UIImage(contentsOfFile: path) else { print("could not find: \(name).\(ext)") return nil } return Image(uiImage: image) } }
内容的提问来源于stack exchange,提问作者soleil
相关产品推荐
相关产品推荐

