Swift inout 如何在未更改时不复制回属性,以不触发对象 setter

标签 swift inout

according to the docs

You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.



但是如果结果根本没有改变,如何不复制回来

我有一个数据库解析器
分配 attr然而,只有当它的值发生变化时,随着 inout 的行为,attr始终设置传入的(将我的数据库对象标记为脏和更改:/)
func importStringAttribute(_ json: JSON, _ key: String, _ attr: inout String?) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != attr {
        attr = v
    }
}

// the myDBObject.someAttr is always set 
importStringAttribute(json, "someAttr", &myDBObject.someAttr)

有没有办法修改,所以只有在传入的属性真正改变时才设置值?

最佳答案

就是这样inout作品。你不能改变这一点。 inout字面意思是“在开始时将值复制到函数中,并在结束时将值复制出函数”。它不做任何分析来决定是否在运行时触及该值。

一种解决方案是检查观察者中的平凡集,例如:

var someAttr: String? {
    didSet {
        guard someAttr != oldValue else { return }
        ...
    }
}

作为另一种方法,我建议使用键路径。假设数据库对象是一个引用类型(类),我相信下面会做你想做的:
func importStringAttribute(_ json: JSON, _ key: String, db: Database,
                           attr: ReferenceWritableKeyPath<Database, String?>) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != db[keyPath: attr] {
        db[keyPath: attr] = v
    }
}

调用时间稍长,因为您需要传递数据库本身:
importStringAttribute(json, "someAttr", db: myDBObject, attr: \.someAttr)

通过将方法附加到数据库(尽管您仍然必须传递数据库,就像 self 一样),这可以变得更漂亮一点:
extension Database {
    func importStringAttribute(_ json: JSON, _ key: String,
                               _ attr: ReferenceWritableKeyPath<Database, String?>) {
        if !json[key].exists() {
            return
        }
        if let v = json[key].string, v != self[keyPath: attr] {
            self[keyPath: attr] = v
        }
    }

}

myDBObject.importStringAttribute(json, "someAttr", \.someAttr)

对于您关于在类型上进行泛型的问题,这非常简单(我刚刚添加了 <Obj: AnyObject> 并将对“db”的引用更改为“obj”):
func importStringAttribute<Obj: AnyObject>(_ json: JSON, _ key: String, obj: Obj,
                           attr: ReferenceWritableKeyPath<Obj, String?>) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != obj[keyPath: attr] {
        obj[keyPath: attr] = v
    }
}

关于Swift inout 如何在未更改时不复制回属性,以不触发对象 setter ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60886752/

相关文章:

swift - 室内导航系统利用计算机视觉进行大面积测绘的解决方案是什么?

ios - 如何同时观察两个用户之间的所有 firebase 数据库事件?

swift - Inout 不使用 SubClass 对象抛出无法将不可变值作为 inout 参数传递

ios - 更改初始行 pickerView

ios - 在 UIView 上应用渐变不起作用

swift - 在 Swift 3 中为闭包内的 inout 参数赋值

ios - Swift 中的 "mutating"函数和 "inout"参数有什么区别吗?

swift 3 更新 swift 2 的语法

kotlin - 在Kotlin中,如何检查输入是否仅为字母

swift - Swift 中的函数参数类型