【问题标题】:More elegant way to assign optionals to a lazy property将选项分配给惰性属性的更优雅的方式
【发布时间】:2020-05-22 09:08:04
【问题描述】:

假设我们有一个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
} 

因此,如果我们有很多 optionals 和 lazy 变量以及一些可选链接情况,我们将有大量重复代码。

有什么更优雅的方法来做到这一点? (也许使用运算符?可选的扩展?)

请注意这不是为了优化。总结了这个示例,如果没有要显示的数据,您不想添加 UI 元素时会发生原始问题。在其他情况下也是如此。

【问题讨论】:

  • 这似乎是过早的优化。您是否真的对创建带有空图像的UIImageView 进行基准测试会占用大量资源? AFAIK 这样做的计算成本不应该很高,因此您的优化似乎为时过早。
  • 这不是为了优化。想象一下,如果没有要显示的数据,我不想添加子视图。此外,UI 元素并不简单imageViews,而且相当昂贵。 @DávidPásztor

标签: swift optional lazy-evaluation


【解决方案1】:

一种方法是使用这样的运算符:

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 = $0 }

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

【讨论】:

    【解决方案2】:

    使用键路径,我已经能够将你正在做的事情提取到一个函数中:

    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)
        }
    }
    

    我不确定它是否“更好”...

    你也可以把它写成你的类中的一个方法:

    func assignNonNilImage<V>(_ keyPath: ReferenceWritableKeyPath<Foo, V>, _ value: V?) {
        if let nonNilValue = value {
            self[keyPath: keyPath] = nonNilValue
        }
    }
    

    【讨论】:

    • 它对UIImageUIImageView 非常具体。是否可以使其更通用,适用于所有类型的作业?
    • @MojtabaHosseini 这就是我在答案的第一个版本中尝试做的,但失败了:-(。例如,要处理UILabel.text,您需要编写另一种方法接受KeyPath&lt;R, UILabel&gt;String?,并分配给text 属性。不过我仍在努力改进...
    • @MojtabaHosseini 啊哈!我想到了!查看编辑。
    • 优秀。但不幸的是,我意识到调用\.imageView.image 会初始化imageView。 (最初的问题是在需要之前不要接触懒惰的人。)
    • 如果我通过nil,它会按预期工作。如果我传递一个包含nil 的变量,它就会变得初始。奇怪!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    • 2011-08-10
    • 1970-01-01
    • 2011-10-15
    相关资源
    最近更新 更多