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/