将可选项分配给惰性 属性 的更优雅的方式
More elegant way to assign optionals to a lazy property
假设我们有一个 lazy imageView
并且我们想要初始化它 只有 如果有图像要分配。所以我们需要每次检查图像值:
lazy var imageView1 = UIImageView()
lazy var imageView2 = UIImageView()
var image: UIImage?
var someOptional: SomeType?
func addImage1IfNeeded() {
guard let image = image else { return }
imageView1.image = image
}
func addImage2IfNeeded() {
guard let image = someOptional?.someChildOptional?.image else { return }
imageView2.image = image
}
所以如果我们有很多 optional
和 lazy
变量和一些 可选链接 情况,我们将有大量重复代码。
更优雅的方法是什么? (也许使用操作员?可选的扩展名?)
请注意这不是为了优化。这个例子被总结了,当你想在没有数据显示的情况下不添加 UI 元素时,原始问题就会发生。还有其他情况。
使用键路径,我已经能够将你正在做的事情提取到一个函数中:
func assignNonNilImage<R, V>(_ root: R, _ keyPath: ReferenceWritableKeyPath<R, V>, _ value: V?) {
if let nonNilValue = value {
root[keyPath: keyPath] = nonNilValue
}
}
用法:
class Foo {
lazy var imageView = UIImageView()
var image: UIImage?
func f() {
// here!
assignNonNilImage(self, \.imageView.image!, image)
}
}
虽然我不确定它是否存在 "better"...
您也可以在 class:
中将其写为方法
func assignNonNilImage<V>(_ keyPath: ReferenceWritableKeyPath<Foo, V>, _ value: V?) {
if let nonNilValue = value {
self[keyPath: keyPath] = nonNilValue
}
}
一种方法是使用这样的运算符:
infix operator ?=>
func ?=>(lhs: Any?, rhs: @autoclosure ()->()) {
guard lhs != nil else { return }
rhs()
}
用法:
image ?=> (imageView1.image = image)
我不知道我们是否可以合并第一个和最后一个参数,因为它们总是相同的。
更新 - 选项 2
关注@Sweeper 的评论:
func ?=><T>(lhs: T?, rhs: (T)->()) {
guard let lhs = lhs else { return }
rhs(lhs)
}
用法:
someOptional?.someChildOptional?.image = { imageView2.image = [=13=] }
对于较长的可选更改更好,但需要花括号和 $
参数(我忘了它的名字)
假设我们有一个 lazy imageView
并且我们想要初始化它 只有 如果有图像要分配。所以我们需要每次检查图像值:
lazy var imageView1 = UIImageView()
lazy var imageView2 = UIImageView()
var image: UIImage?
var someOptional: SomeType?
func addImage1IfNeeded() {
guard let image = image else { return }
imageView1.image = image
}
func addImage2IfNeeded() {
guard let image = someOptional?.someChildOptional?.image else { return }
imageView2.image = image
}
所以如果我们有很多 optional
和 lazy
变量和一些 可选链接 情况,我们将有大量重复代码。
更优雅的方法是什么? (也许使用操作员?可选的扩展名?)
请注意这不是为了优化。这个例子被总结了,当你想在没有数据显示的情况下不添加 UI 元素时,原始问题就会发生。还有其他情况。
使用键路径,我已经能够将你正在做的事情提取到一个函数中:
func assignNonNilImage<R, V>(_ root: R, _ keyPath: ReferenceWritableKeyPath<R, V>, _ value: V?) {
if let nonNilValue = value {
root[keyPath: keyPath] = nonNilValue
}
}
用法:
class Foo {
lazy var imageView = UIImageView()
var image: UIImage?
func f() {
// here!
assignNonNilImage(self, \.imageView.image!, image)
}
}
虽然我不确定它是否存在 "better"...
您也可以在 class:
中将其写为方法func assignNonNilImage<V>(_ keyPath: ReferenceWritableKeyPath<Foo, V>, _ value: V?) {
if let nonNilValue = value {
self[keyPath: keyPath] = nonNilValue
}
}
一种方法是使用这样的运算符:
infix operator ?=>
func ?=>(lhs: Any?, rhs: @autoclosure ()->()) {
guard lhs != nil else { return }
rhs()
}
用法:
image ?=> (imageView1.image = image)
我不知道我们是否可以合并第一个和最后一个参数,因为它们总是相同的。
更新 - 选项 2
关注@Sweeper 的评论:
func ?=><T>(lhs: T?, rhs: (T)->()) {
guard let lhs = lhs else { return }
rhs(lhs)
}
用法:
someOptional?.someChildOptional?.image = { imageView2.image = [=13=] }
对于较长的可选更改更好,但需要花括号和 $
参数(我忘了它的名字)