Sponsor Link
環境&対象
- macOS Monterey 12.1 beta3
- Xcode 13.2 beta2
- iOS 15
この記事のコードは、Playground で動作します
KeyPath
Apple のドキュメントは、こちら。
”A key path from a specific root type to a specific resulting value type” と書かれています。
意訳すると、”指定型の特定プロパティへの key path” でしょうか。
# KeyPath の説明に key path が含まれているのって・・・
簡単な例: KeyPath
// (1)
struct MyStruct {
let constA: Int
var varB: Int
}
// (2)
let pathToConstA: KeyPath<MyStruct, Int> = \MyStruct.constA
let myStruct = MyStruct(constA: 1, varB: 2)
// (3)
print(myStruct[keyPath: pathToConstA]) // print-out: 1
- constA と varB というプロパティを持つ struct を定義します
- constA というプロパティを指し示す KeyPath を定義します。
- KeyPath を使って、struct のプロパティにアクセスします
PartialKeyPath
普段使うコードで、\<struct名>.<プロパティ名> という指定ってあまりしませんよね。\.<プロパティ名> という使い方が多い気がします。
その時に使用されているものが、PartialKeyPath です。Apple のドキュメントは、こちら。
ベースとなる型とプロパティ名があれば、プロパティ型は、推測できるので、指定することが不要となります。
struct MyStruct {
let constA: Int
var varB: Int
}
struct MyStruct2 {
let constA: Int
var varB: Int
}
let myStruct = MyStruct(constA: 1, varB: 2)
// (1)
let pathToConstA: KeyPath<MyStruct, Int> = \MyStruct.constA
print(myStruct[keyPath: pathToConstA])
// (2)
let partialKeyPathToConstA: PartialKeyPath<MyStruct> = \.constA
print(myStruct[keyPath: partialKeyPathToConstA])
- KeyPath の使用例
- PartialKeyPath の使用例
WritableKeyPath
先ほど作成した KeyPath を使用してプロパティを更新しようとするとどうなるかやってみます。
import Foundation
struct MyStruct {
let constA: Int
var varB: Int
}
var myStruct = MyStruct(constA: 1, varB: 2)
let pathToVarB: KeyPath<MyStruct, Int> = \MyStruct.varB
myStruct[keyPath: pathToVarB] = 3 // error: cannot assign through subscript: 'pathToVarB' is a read-only key path
print(myStruct[keyPath: pathToVarB])
KeyPath は read-only だとしてコンパイルエラーになります
struct 作成も var 定義に変更していますし、プロパティも var として定義していてもエラーになっています。
このようなケースで必要となるのが、WritableKeyPath です。Apple のドキュメントは、こちら。
import Foundation
struct MyStruct {
let constA: Int
var varB: Int
}
var myStruct = MyStruct(constA: 1, varB: 2)
let pathToVarB: WritableKeyPath<MyStruct, Int> = \MyStruct.varB
myStruct[keyPath: pathToVarB] = 3
print(myStruct[keyPath: pathToVarB]) // print-out: 3
KeyPath を引数で受ける関数
例えば、KeyPath によって指定されたプロパティの値を表示する関数は以下のようになります。
func printMyStructMember(_ myStruct: MyStruct,_ myKeyPath: PartialKeyPath<MyStruct>) {
print(myStruct[keyPath: myKeyPath])
}
上記の関数を使用するコードは、以下のようになります。
var myStruct = MyStruct(constA: 1, varB: 2)
printMyStructMember(myStruct, \.constA)
ようやく、見慣れたコード(\.<プロパティ名>)がでてきました。
引数の型が、KeyPath の時には、渡す側で \MyStruct.varB と書かなければいけませんが、もともと対象の struct はMyStruct なので、PartialKeyPath で受け取るのは適切な API 設計と言えると思います。
KeyPath についての考察
KeyPath を使用することで、処理対象のプロパティ名を引数として渡す(指定する)ことができるようになります。
元ネタ?
以下の YouTube をみていて、改めて KeyPath を理解したくて 整理してみました。
まとめ:KeyPath を理解する
- 型のプロパティへのアクセス方法の1つ
- PartialKeyPath を指定すると、型を都度指定しなくとも良くなる
- プロパティの更新には WritableKeyPath を使用する
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Swift 学習におすすめの本
詳解Swift
Swift の学習には、詳解 Swift という書籍が、おすすめです。
著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。
最新版を購入するのがおすすめです。
現時点では、上記の Swift 5 に対応した第5版が最新版です。
Swift ポケットリファレンス
Swift を学んでも、プログラミング言語の文法を全て記憶しておくことは無理なので、ちょっとした文法の確認をするために、リファレンス本を手元に置いておくと便利です。
Swift4 までしか対応していないので、相違点を理解して参照する必要があります。
Sponsor Link