问题描述
如果属性为零,我的应用程序需要显示从 CoreData 实体中提取的图像,并具有 2 个回退级别。首先,它查看 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...
}
}
这似乎创建了无休止的合并默认值级联。有没有更好的办法?
解决方法
确实没有更优雅的解决方案,但您可以将其简化为单一级别的 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)
}
}
,
为 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")!