In Swift 4 many on the Foundation team have discussed how much easier it is to use keyPaths as compared to Swift 3. This begs the question... What is a keyPath? Seriously, I can't find any clear resources.
-
2https://developer.apple.com/documentation/swift/key_path_expressions; https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/BasicPrinciples.html#//apple_ref/doc/uid/20002170-BAJEAIEE – jscs Jun 09 '17 at 02:10
-
1I liked this blogpost: https://www.klundberg.com/blog/swift-4-keypaths-and-you/ – pushkarnk Nov 14 '17 at 13:29
-
1https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md – pushkarnk Nov 14 '17 at 14:31
2 Answers
Objective-C has the ability to reference a property dynamically rather than directly. These references, called keypaths. They are distinct from direct property accesses because they don't actually read or write the value, they just stash it away for use.
Let define a struct called Cavaliers and a struct called Player, then create one instance of each:
// an example struct
struct Player {
var name: String
var rank: String
}
// another example struct, this time with a method
struct Cavaliers {
var name: String
var maxPoint: Double
var captain: Player
func goTomaxPoint() {
print("\(name) is now travelling at warp \(maxPoint)")
}
}
// create instances of those two structs
let james = Player(name: "Lebron", rank: "Captain")
let irving = Cavaliers(name: "Kyrie", maxPoint: 9.975, captain: james)
// grab a reference to the `goTomaxPoint()` method
let score = irving.goTomaxPoint
// call that reference
score()
The last lines create a reference to the goTomaxPoint() method called score. The problem is, we can't create a reference to the captain's name property but keypath can do.
let nameKeyPath = \Cavaliers.name
let maxPointKeyPath = \Cavaliers.maxPoint
let captainName = \Cavaliers.captain.name
let cavaliersName = irving[keyPath: nameKeyPath]
let cavaliersMaxPoint = irving[keyPath: maxPointKeyPath]
let cavaliersNameCaptain = irving[keyPath: captainName]
Please test with Xcode 9 or capable snapshot.
- 30,595
- 22
- 143
- 179
- 6,980
- 4
- 33
- 36
-
1if anyone is still around on this - can't you just do irving.captain.name and get Lebron? – PruitIgoe Jun 20 '18 at 16:37
-
Swift KVC
KeyPath is a reference to a property of a type rather than value. It adds a dynamism into language
There are some of them:
KeyPath<Root, Value>- only readWritableKeyPath<Root, Value>- read/write forvarpropertyReferenceWritableKeyPath<Root, Value>- read/write only for reference types[About]PartialKeyPath<Root>AnyKeyPath
You can find that KeyPath is used for shortcuts(e.g. sorting, iterating, filtering), KVO[Example], MemoryLayout[Example], SwiftUI and others more advanced features
Syntax
class SomeClass {
var v: String = "Hello World"
}
Pre Swift v4 - slow and not type safe
@objc //For example var v: String = "Hello world"
let keyPath = #keyPath(SomeClass.v) //keyPath is String Type
//read
someClass.value(forKeyPath: keyPath) //or forKey:
//write
someClass.setValue("Another string", forKeyPath: keyPath) //or forKey:
- Starts from backwards slash
\
let someKeyPath = \SomeClass.v //KeyPath<SomeClass, String>
- If there is a known object you can use
\.
someClass.observe(\.v, options: .new) //someClass1.v
//read
let res = someClass[keyPath: \SomeClass.v]
//write
someClass[keyPath: \.v] = "Another string"
- 21,739
- 5
- 148
- 151