SwiftUIではKeyPathが当たり前のように使われています。
中身を理解するのに、サボっていたKeyPathのキャッチアップをする必要が出てしまったのでやっていきます。
こちらの記事がわかり易かったので、ベース同じコードを引用させて頂いております。
https://qiita.com/BlueEventHorizon/items/dee0eb27fbba83ed8ea9
ソートを例にしたコード
KeyPathの便利さがめっちゃわかる.swift
import Foundation
enum SortOrder {
case ascending
case descending
}
extension Sequence {
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, order: SortOrder = .ascending) -> [Element] {
return sorted { a, b in
switch order {
case .ascending:
return a[keyPath: keyPath] < b[keyPath: keyPath]
case .descending:
return a[keyPath: keyPath] > b[keyPath: keyPath]
}
}
}
}
struct User {
var name: Name
struct Name {
var first: String
var last: String
}
}
let person1 = User(name: .init(first: "Yoshiharu", last: "Yamada"))
let person2 = User(name: .init(first: "Masahiro", last: "Tanaka"))
let people = [person1, person2]
let results = people.sorted(by: \.name.first)
KeyPathが便利となる動機
もしKeyPathがなかったらこのような処理が必要になります。
もしkeyPathがなかったら.swift
let people = [person1, person2]
let results = people.sorted { $0.name.first < $1.name.first }
たとえば、name.firstというキーで比較をしてほしい意図は明確なのに、クロージャを作らないといけませんし、同じプロパティのキーを2度書かないといけないのは面倒です。
これを一度指定すればいいようにできるのが、keyPathです。
sortedに対してkeypath指定をすればいいので
keyPath便利.swift
let results = people.sorted(by: \.name.first)
// let results = people.sorted(by: \User.name.first) でも可能
のように書けます。ファンタスティック!
KeyPathとは
KeyPath.swift
class KeyPath<Root, Value> : PartialKeyPath<Root>
で宣言されています。
今回は、KeyPath<User, String>
となっています。
インスタンスにkeyPath経由でアクセス
sorted.swift
case .ascending:
return a[keyPath: keyPath] < b[keyPath: keyPath]
上記のような辞書形式でアクセスします。キーは keyPath
でないといけません。
感想
あるキーをつかって比較をする。のような場面ではわかりやすく便利になるのが分かりました。
SwiftUI楽しみですね!