I've come up with a, possibly simpler, solution to setting values by key paths on unknown types in a project of my own.
The requirements for the unknown type were :
public weak var subject: (AnyObject & KeyPathDeclaration)!
… where KeyPathDeclaration is :
public protocol KeyPathDeclaration
{
static var keyPaths: [String : AnyKeyPath] { get }
}
extension KeyPathDeclaration
{
public static func keyPathForProperty(name: String) -> AnyKeyPath?
{
return keyPaths[name]
}
}
This is then implemented in a type like this :
struct Person
{
var name: String
var age: Int
}
extension Person : KeyPathDeclaration
{
public static var keyPaths: [String : AnyKeyPath]
{
return ["name" : \Person.name, "age" : \Person.age]
}
}
The problem arises when you need to use one of the key paths to set a value where the exact type of the target object is only known as :
public weak var subject: (AnyObject & KeyPathDeclaration)!
… where trying to use subject[keyPath:_] to set a value provokes an error
"Cannot assign to immutable expression of type 'Any?'"
So, I played around for a bit and started thinking about some of the ideas in this thread. Here's what I came up with.
First, I create a new protocol :
public protocol KeyPathValueSetter
{
func set<valueT>(_ value: valueT?, for keyPath: AnyKeyPath)
}
extension KeyPathValueSetter
{
public func set<valueT>(_ value: valueT, for keyPath: AnyKeyPath)
{
if let keyPath = keyPath as? ReferenceWritableKeyPath<Self, valueT>
{
self[keyPath: keyPath] = value
}
}
}
Then I add in this protocol to the subject's requirements :
public weak var subject: (AnyObject & KeyPathValueSetter & KeyPathDeclaration)!
Now I can set the value on the subject like this :
let keyPath = type(of: subject).keyPathForProperty(name: propertyName)
subject.set(value, for: keyPath)
Not quite a subscript but a lot more concise than some efforts I made to solve this