KeyPath — adalah jalur bertipe ke properti objek di Swift, direpresentasikan sebagai nilai kelas satu. Berbeda dengan kunci teks di KVC (Key-Value Coding), KeyPath diperiksa oleh kompiler pada tahap kompilasi: kompiler mengetahui tipe objek root, tipe properti itu sendiri dan dapat menjamin bahwa jalur tersebut ada. KeyPath digunakan di Combine untuk pengikatan reaktif, di SwiftUI untuk binding dua arah dan di perpustakaan standar untuk mengurutkan dan memfilter koleksi. Menurut Apple Developer, 2025, KeyPath adalah blok bangunan fundamental untuk pemrograman fungsional di Swift.
Poin Utama
KeyPath — adalah tipe dari perpustakaan standar Swift yang mewakili jalur ke properti suatu objek. Berbeda dengan akses manual ke properti melalui titik (object.property) atau kunci teks (value(forKey:)), KeyPath adalah objek kelas satu: dapat diteruskan sebagai argumen, disimpan dalam variabel, dan digabungkan.
KeyPath ditulis dengan garis miring terbalik dan jalur ke properti: \Person.name. Jalurnya bisa bersarang: \Person.address.city. Kompiler memeriksa bahwa Person memiliki properti name dan bahwa name benar-benar bertipe String. Jika properti tidak ada atau tipenya salah, kode tidak akan dikompilasi.
struct Person: Codable {
let name: String
let age: Int
var isActive: Bool
}
// KeyPath (hanya baca)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]
Akses ke properti melalui KeyPath dilakukan melalui subscript object[keyPath: path]. Untuk properti ReadOnly, KeyPath digunakan. Jika properti dapat diubah (var), WritableKeyPath tersedia. Untuk tipe referensi — ReferenceWritableKeyPath, memungkinkan perubahan properti melalui KeyPath itu sendiri.
KeyPath memiliki hierarki subtipe yang mencerminkan tingkat akses ke properti. Hierarki dasar: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Setiap subtipe menambahkan kemampuan.
KeyPath — hanya baca. WritableKeyPath — baca dan tulis untuk tipe nilai (struct). ReferenceWritableKeyPath — baca dan tulis untuk tipe referensi (class). Swift secara otomatis memilih subtipe yang tepat berdasarkan konteks.
| Tipe | Akses | Tipe objek | Perubahan |
|---|---|---|---|
| KeyPath | ReadOnly | Apapun | Tidak |
| WritableKeyPath | ReadWrite | Tipe nilai (inout) | Melalui konteks mutating |
| ReferenceWritableKeyPath | ReadWrite | Tipe referensi | Penugasan langsung |
// WritableKeyPath untuk tipe nilai
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true
// ReferenceWritableKeyPath untuk kelas
class User: NSObject {
@objc dynamic var name: String = ""
}
let user = User()
let refPath: ReferenceWritableKeyPath<User, String> = \User.name
user[keyPath: refPath] = "Charlie"
Perbedaan penting: untuk tipe nilai, pengaturan melalui KeyPath memerlukan var (konteks inout), dan untuk tipe referensi — properti yang dapat diubah. Ini sesuai dengan semantik umum Swift: tipe nilai diteruskan berdasarkan nilai, sehingga perubahan memerlukan mutabilitas wadah.
KeyPath memainkan peran sentral di Combine dan SwiftUI. Di Combine, operator assign menggunakan KeyPath untuk mengikat nilai penerbit ke properti objek. Di SwiftUI, Binding menggunakan KeyPath untuk pengikatan dua arah antara model dan tampilan.
Operator assign(to:on:) menerima ReferenceWritableKeyPath dan sebuah objek. Ketika penerbit mengirim nilai, nilai tersebut secara otomatis ditulis ke properti yang ditentukan. Ini adalah cara deklaratif untuk mengelola status tanpa penugasan manual.
import Combine
class SettingsViewModel: ObservableObject {
@Published var volume: Float = 0.5
var cancellables = Set<AnyCancellable>()
func bindSlider(publisher: AnyPublisher<Float, Never>) {
publisher
.assign(to: \SettingsViewModel.volume, on: self)
.store(in: &cancellables)
}
}
Di SwiftUI, @Binding menggunakan KeyPath untuk menghubungkan View induk dan anak. Induk meneruskan Binding
KeyPath memungkinkan penulisan fungsi pengurutan dan pemfilteran yang fleksibel dan aman tipe. Alih-alih meneruskan closure setiap kali, Anda dapat meneruskan KeyPath ke properti yang ingin Anda gunakan untuk mengurutkan koleksi. Ini membuat kode lebih bersih dan mengurangi duplikasi.
Fungsi sorted
extension Sequence {
func sorted<Value: Comparable>(
by keyPath: KeyPath<Element, Value>,
ascending: Bool = true
) -> [Element] {
ascending
? self.sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
: self.sorted { $0[keyPath: keyPath] > $1[keyPath: keyPath] }
}
}
let sortedByName = people.sorted(by: \Person.name)
let sortedByAgeDesc = people.sorted(by: \Person.age, ascending: false)
Implementasi semacam itu mengurutkan berdasarkan properti Comparable apa pun tanpa menulis closure. Untuk mengurutkan berdasarkan nama belakang, cukup ubah KeyPath: \Person.lastName. Jika perlu mengurutkan berdasarkan kunci khusus (misalnya, panjang nama), map digunakan di dalamnya — pengembang masih dapat menulis closure sendiri untuk kasus non-standar.
AnyKeyPath — adalah tipe dasar dalam hierarki KeyPath yang menghapus informasi tentang tipe spesifik root dan nilai. AnyKeyPath tidak tahu pada tipe objek apa ia dipanggil dan tipe nilai apa yang dikembalikan. Ini berguna untuk menyimpan KeyPath heterogen di koleksi dan untuk refleksi.
AnyKeyPath digunakan ketika Anda perlu menyimpan daftar jalur ke properti yang berbeda dari tipe yang berbeda. Misalnya, di konfigurator UI, di mana setiap jalur mengonfigurasi properti tertentu, dan tipe properti mungkin berbeda. AnyKeyPath memungkinkan kerja yang seragam dengan semua jalur.
protocol Configurable {
func apply(_ keyPath: any PartialKeyPath<Self>, value: any)
}
extension Configurable {
func configure(_ pairs: (any KeyPath<Self, any>, any)...) {
for (path, value) in pairs {
apply(path, value: value)
}
}
}
extension Person: Configurable { }
// Memungkinkan konfigurasi properti melalui AnyKeyPath
AnyKeyPath memerlukan konversi tipe saat mengambil nilai, karena tipe spesifik telah dihapus. Untuk keamanan tipe yang lengkap, KeyPath
KeyPath secara signifikan lebih berkinerja daripada kunci teks KVC (value(forKey:)). Kunci teks dihitung melalui mekanisme runtime Objective-C, termasuk penguraian teks, pencarian di runtime, dan konversi tipe. KeyPath adalah mekanisme statis yang didasarkan pada struktur asli Swift.
Menurut pengujian, KeyPath rata-rata 10-20 kali lebih cepat daripada value(forKey:) untuk akses properti. Perbedaan ini disebabkan oleh tidak adanya pencarian runtime dan dispatch dinamis. KeyPath langsung mengakses offset properti di memori dengan optimasi kompiler yang memadai.
func readWithKeyPath(person: Person) -> String {
person[keyPath: \Person.name]
}
func readWithKVC(person: Person) -> String {
person.value(forKey: "name") as! String
}
KVC tidak hanya lebih lambat, tetapi juga tidak aman dari segi tipe: teks “name” mungkin tidak ada, dan konversi as! String bisa gagal. KeyPath menjamin keberadaan properti dan kebenaran tipe pada tahap kompilasi. Untuk bagian yang kritis terhadap kinerja (animasi, daftar ribuan elemen), KeyPath adalah satu-satunya pilihan yang tepat.
Pertanyaan Umum
KeyPath — adalah penunjuk ke properti objek yang dapat diteruskan seperti nilai biasa. Alih-alih menulis person.name, Anda membuat jalur \Person.name dan menggunakannya untuk membaca atau menulis properti di instance Person mana pun.
KeyPath — hanya baca. WritableKeyPath — untuk membaca dan menulis tipe nilai (struct) melalui konteks inout. ReferenceWritableKeyPath — untuk membaca dan menulis tipe referensi (class) tanpa kondisi tambahan.
KeyPath banyak digunakan di Combine (assign(to:on:)), SwiftUI (Binding, FocusState), pengurutan koleksi (sorted(by:)), Core Data (NSSortDescriptor) dan untuk akses aman ke properti bersarang.
Ya, KeyPath sepenuhnya aman tipe. Kesalahan di jalur (salah ketik, tipe salah) terdeteksi pada tahap kompilasi, bukan di runtime. value(forKey:) menggunakan teks dan bisa gagal dengan NSUndefinedKeyException jika kunci tidak ada.
Secara langsung — tidak, Swift tidak mendukung pembuatan KeyPath secara dinamis dari teks. Namun, Anda dapat menggunakan AnyKeyPath untuk menyimpan dan meneruskan KeyPath yang diperoleh secara statis. Untuk akses dinamis ke properti berdasarkan teks, gunakan value(forKey:) dengan Objective-C runtime.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga