Допустим, у меня есть следующий класс:
class User: NSObject {
var name = "Fred"
var age = 24
var email = "fred@freddy.com"
var married = false
}
Я хочу написать обобщенную c функцию, которая принимает список KeyPath
s для известного типа класса, прочитайте значения и распечатать на экран. Проблема в том, что я не могу получить следующий код для компиляции, так как тип KeyPath
s Value
неизвестен и будет отличаться для каждого раза. Что мне нужно сделать, чтобы это работало в общем?
Рассмотрим следующее:
struct KeyPathProperties<T> {
var name: String
var relatedKeyPaths: [KeyPath<T, Any>]
}
extension KeyPath where Root == User {
var properties: KeyPathProperties<Root> {
switch self {
case \Root.name:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
default:
fatalError("Unknown key path")
}
}
}
Эта строка не компилируется:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
с этой ошибкой:
Cannot convert value of type 'KeyPath<User, Int>' to expected element type 'KeyPath<User, Any>'
Это то, что я sh могу сделать, например:
let myUser = User()
var keyPathProps = KeyPathProperties(name: "name", relatedKeyPaths: [\User.age, \User.email])
for keyPath in props.relatedKeyPaths {
print("Value: \(myUser[keyPath: keyPath])")
}
Выше не будет, конечно, компилироваться. По сути, я хочу хранить keyPaths в массиве во время выполнения, поэтому я могу в определенный момент времени получить значения из User
. Мне нужно знать, могу ли я переписать вышеупомянутое каким-либо образом, чтобы компилятор мог безопасно и правильно определить тип значения keyPath во время выполнения.
Это концептуальный вариант использования для гораздо более сложной архитектуры Проблема, которую я пытаюсь решить с помощью, надеюсь, меньшего количества кода.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:
Во время выполнения я буду sh, чтобы отслеживать изменяемые свойства - эти свойства хранятся в Измененный массив Props в каждом объекте / экземпляре. В какой-то момент во время выполнения я смогу sh перечислить этот массив KeyPaths и напечатать их значения следующим образом:
for modifiedKeyPath in self.modifiedProps {
print ("\(self[keyPath: modifiedKeyPath])"
}
Короче - мне нужно иметь возможность перехватить обобщенный c тип KeyPath в пределах KeyPathProperties
. Как мне этого добиться?
СТОРОННОЕ ПРИМЕЧАНИЕ: я уже могу легко добиться этого, используя KeyPaths на основе строковых стилей Swift 3 (добавив @objc
к свойствам класса). Я могу сохранить массив keyPaths как строки, а затем сделать:
let someKeyPath = #keyPath(User.email)
...
myUser.value(forKeyPath: someKeyPath)
Я просто не могу сделать это с помощью Swift 4 KeyPaths в общем.