Так работает 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)
Это можно сделать немного красивее, если присоединить метод к базе данных (хотя вам все равно придется передавать базу данных, как и себя):
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)
К вашему вопросу о сделать это generi c над типами, это очень просто (я просто добавил <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
}
}