这是如何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
}
}