If I have
class Info {
var name: String?
}
class User {
var info: Info?
}
class WrappedClass {
var user: User = User()
}
let nameKeyPath = \WrappedClass.user.info?.name //Gets me KeyPath
let referencedNameKeyPath = \WrappedClass.user.info!.name //Gets me ReferenceWritableKeyPath
nameKeyPath
gets me a KeyPath
which I can't later on use to modify the name value, but if I force unwrap it I get a ReferenceWritableKeyPath
which is what I'm after.
Unfortunately using referencedNameKeyPath
with a nil value along the line expectedly crashes, due to unexpectedly finding nil.
My question is is there a way to convert the KeyPath
to a ReferenceWritableKeyPath
or somehow unwrap it along the way?
You can also use optional chaining on keypaths. Create two keypaths one for user and the other one for name in info.
let infoKeyPath = \WrappedClass.user.info
let nameKeyPath = \Info.name
Now, use optional chaining with keypath and it will yield String? as the result.
let name = wrappedInstance[keyPath: infoKeyPath]?[keyPath: nameKeyPath]
Try having the key path as a computed optional variable. Like that:
class WrappedClass {
var user: User = User()
var nameKeyPath: ReferenceWritableKeyPath<WrappedClass, String?>? {
guard let _ = user.info else { return nil }
return \WrappedClass.user.info!.name
}
}
You still end up with the force unwrap notation but it should not cause any issues since you specifically guard for it.
That way you can use the computed key path in a safe and convenient way:
let instance = WrappedClass()
if let nameKeyPath = instance.nameKeyPath {
instance[keyPath: nameKeyPath] = "Nikola"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With