【问题标题】:CoreData, UIImage and UnwrappingCoreData、UIImage 和展开
【发布时间】:2021-04-26 19:35:33
【问题描述】:

如果属性为 nil,我的应用需要显示从具有 2 级回退的 CoreData 实体中提取的图像。首先,它查看 Entity.bannerImageBlob 属性(二进制数据/外部存储)并尝试从中构建 UIImage。如果失败,它将在资产目录中查找名为 Entity.bannerImageName 的资产,如果不存在,则使用资产目录中存在的“banner-placeholder”。

因为实例化 UIImage 可能会失败并且必须解包,并且因为核心数据属性都是可选的,所以我进入了一个 if-pyramid/unwrapping 循环,看起来我正在处理这个问题。

(其中一些复杂性是从将图像存储在资产目录中迁移到将它们存储在 CoreData/文件系统中的结果,但我需要确保我可以在所有这些方案之间进行通信。)

这是我的 CoreData 实体扩展中的便捷变量。实体属性有一个尾随下划线。这就是我希望它工作的方式(此代码不起作用)。


var bannerImage: Image {
    let fallback = UIImage(named: bannerImageName_ ?? "banner-placeholder")
    
    if let blobImage = UIImage(data: bannerImageBlob_) { // error: data? must be unwrapped...
        return Image(uiImage: blobImage)
    } else {
        return Image(uiImage: fallback) // error: UIImage? must be unwrapped...
    }
}

这似乎创建了无穷无尽的级联默认值。有没有更好的办法?

【问题讨论】:

  • 为什么不使用return a ?? b ?? c之类的东西,如果不是nil则返回a,否则返回b,如果不是nil,则返回c。由于最后一个图像存在于您的资产目录中,您应该能够在调用 Image(uiImage:) 时强制打开它
  • 在 UIImage 的上下文中如何工作?即使使用已知存在的值调用 UIImage 似乎也需要解包。
  • 查看我的更新评论,UIImage(named: "banner-placeholder")!
  • 完全。最终还是这样:return UIImage(data: bannerImageBlob_ ?? <#default value>) ?? UIImage(named: bannerImageName_ ?? <#default value>) ?? UIImage(named: "banner-placeholder")!

标签: swift image uikit uiimage


【解决方案1】:

为 UIImage 创建一个扩展并添加带有可选参数的新工厂方法

extension UIImage {
    static func create(data: Data?) -> UIImage? {
         guard let data = data else { return nil }
         return UIImage(data: data)
    }

    static func create(named: String?) -> UIImage? {
         guard let string = named else { return nil }
         return UIImage(named: string)
    }
}

然后

return UIImage.create(data: bannerImageBlog_) ??
    UIImage.create(named: bannerImageName_) ??
    UIImage(named: "banner-placeholder")!

【讨论】:

  • 两者都很好用。归档使用。谢谢!
  • 修复缺少的返回值声明
【解决方案2】:

实际上没有更优雅的解决方案,但您可以将其简化为单级 if-else 语句:

var bannerImage: Image {
    if let data = bannerImageBlob_,
       let let blobImage = UIImage(data: data) {
        return Image(uiImage: blobImage)
    } else if let imageName = bannerImageName_,
              let image = UIImage(named: imageName) {
        return Image(uiImage: image)
    } else {
        let fallback = UIImage(named: "banner-placeholder")!
        return Image(uiImage: fallback)
    }
}

您可能希望将图像缓存在内存中,而不是每次都计算,如果您有一个可以用作键的字符串someUniqueId_,则可能看起来像这样:

static fileprivate let imageCache = NSCache<NSString, UIImage>()

var bannerImage: Image {
    if let cachedImage = Self.imageCache.object(forKey: someUniqueId_) {
        return Image(uiImage: cachedImage)
    } else {
        let uiImage: UIImage = {
            if let data = bannerImageBlob_,
               let let blobImage = UIImage(data: data) {
                return blobImage
            } else if let imageName = bannerImageName_,
                      let image = UIImage(named: imageName) {
                return image
            } else {
                return UIImage(named: "banner-placeholder")!
            }
        }()
        Self.imageCache.setObject(uiImage, forKey: someUniqueId_)
        return Image(uiImage: uiImage)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-11
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多