将可选项分配给惰性 属性 的更优雅的方式

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
} 

所以如果我们有很多 optionallazy 变量和一些 可选链接 情况,我们将有大量重复代码。

更优雅的方法是什么? (也许使用操作员?可选的扩展名?)

请注意这不是为了优化。这个例子被总结了,当你想在没有数据显示的情况下不添加 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=] }

对于较长的可选更改更好,但需要花括号和 $ 参数(我忘了它的名字)