Swift CoreData、UIImage和展开

Swift CoreData、UIImage和展开,swift,image,uikit,uiimage,Swift,Image,Uikit,Uiimage,如果属性为nil,我的应用程序需要显示从CoreData实体中提取的图像,该实体具有两级回退。首先,它查看Entity.bannerImageBlob属性(二进制数据/外部存储),并尝试从中构建UIImage。如果失败,则在资产目录中查找名为Entity.bannerImageName的资产,如果不存在,则使用资产目录中存在的“banner占位符” 因为实例化UIImage可能会失败,并且必须展开,而且核心数据属性都是可选的,所以我进入了一个if棱锥/展开循环,似乎我在做这件事时不够优雅 (这种

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

因为实例化UIImage可能会失败,并且必须展开,而且核心数据属性都是可选的,所以我进入了一个if棱锥/展开循环,似乎我在做这件事时不够优雅

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

下面是我的CoreData实体扩展的方便变量。实体属性后面有一个下划线。这是我希望它工作的方式(此代码不工作)


这似乎创建了一个无休止的聚合默认值的级联。有更好的方法吗?

没有更优雅的解决方案,但您可以将其简化为单个级别的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\uuu
可以用作键,则可能会出现如下情况:

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)
    }
}
静态fileprivate let imageCache=NSCache() var bannerImage:图像{ 如果让cachedImage=Self.imageCache.object(forKey:someUniqueId\ux){ 返回图像(uiImage:cachedImage) }否则{ 让uiImage:uiImage={ 如果let data=bannerImageBlob_2;, 让blobImage=UIImage(数据:数据){ 返回blobImage }否则如果让imageName=bannerImageName, 让image=UIImage(名称:imageName){ 返回图像 }否则{ 返回UIImage(名为:“横幅占位符”)! } }() Self.imageCache.setObject(uiImage,forKey:someUniqueId) 返回图像(uiImage:uiImage) } }
创建UIImage的扩展,并添加采用可选参数的新factory方法

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")!

为什么不使用类似于
返回a??Bc
,即如果不是零,则返回a,否则如果不是零,则返回b,否则返回c。由于资产目录中存在最后一个映像,因此在调用image(uiImage:)时,应该能够强制展开它。在uiImage的上下文中,这将如何工作?即使使用已知存在的值调用UIImage,似乎也需要展开UIImage。请参阅我更新的注释,
UIImage(名为:“横幅占位符”)全部。它仍然是这样结束的:
returnuiimage(数据:bannerImageBlob)??UIImage(名称:bannerImageName)??UIImage(名为:“横幅占位符”)两者都很有效。归档以备使用。谢谢修复了缺少返回值声明的问题
return UIImage.create(data: bannerImageBlog_) ??
    UIImage.create(named: bannerImageName_) ??
    UIImage(named: "banner-placeholder")!