KeyPath
date
Jun 13, 2024
slug
keypath
status
Published
tags
swift
summary
The article discusses the KeyPath type, what it can be used for, and provides several examples that seem to me to be indicative and can improve the readability and quality of the project code.
type
Post
SemanticsTypesUsageAlternative protocolIn functionsSwitch case by properties of a non-enum objectWrapper over higher order functionsSome more examplesUseful links
Semantics
KeyPath is a type that represents references to properties of an object. Its use can be seen in expressions where the
\.
notation is used.KeyPath refers to a property or index of a type, so its only use is to read/write to that property using separate semantics.
Models used in the examples below:
In practice, accessing the key path for the objects described above will be as follows:
Note that the <#property#>[keyPath: <#key#>] initializer is part of the Swift language and is available for any type.
Types
Swift has five KeyPath types:
KeyPath
: Access a read-only property whose type can be either value semantics or reference semantics;
PartialKeyPath
: Only for reading. Can refer to any property of an object, without needing to know its exact type;
AnyKeyPath
: Only for reading. This is the most common type of key path. It can refer to any property of any object type, but does not provide any information about the type of the object or the type of the value it refers to;
WritableKeyPath
: Provides read/write access to a mutable property with value semantics. (struct
/enum
).
ReferenceWritableKeyPath
: Provides reading and writing for a mutable property with reference semantics (for example,class
).
Usage
It is important to understand that KeyPath does not add any new behavior to your implementation and in most cases you can do without it. However, you can find areas that will improve readability or add more context to what's happening in your code.
Alternative protocol
In SwiftUI, we can create views from a collection of
Identifiable
data. The only requirement of the Identifiable
protocol is a Hashable
variable named id
.In functions
Let's add a few objects with which we can demonstrate how the functions work.
Higher-order functions operate on instance properties, which can be accessed using the simpler syntax discussed earlier:
Please note that such writing in the reduce, sorted or allSatisfy methods is impossible without additional wrappers over the methods themselves, since they use two arguments.
Switch case by properties of a non-enum object
If the properties of an object are homogeneous, then you can iterate over them in a switch-case construct to obtain values based on some preconditions:
Wrapper over higher order functions
This example shows how you can add context to the map function being executed. If you have a large number of map calls to data sets, you might think about using the following constructs:
The same goes for the filter function:
I mentioned earlier that
KeyPath
cannot be used for functions that require multiple arguments, however there is a way to get around this limitation:Some more examples
As previously stated,
PartialKeyPath
is used when there is no information about the inferred type of the property. To better understand how this works, let's look at an example of a possible implementation of get / set methods in an abstract repository: