KeyPath: konsep kunci dan akses bertipe

Penulis: IT Sectr Diterbitkan: 2026-06-18 Waktu membaca: 10 mnt

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 — jalur bertipe ke properti, diperiksa oleh kompiler
  • WritableKeyPath — subtipe KeyPath untuk properti dengan akses tulis
  • ReferenceWritableKeyPath — untuk properti yang dapat diubah dari tipe referensi
  • Combine menggunakan KeyPath untuk mengikat penerbit ke properti objek
  • AnyKeyPath — varian type-erased untuk menyimpan KeyPath di koleksi

Apa itu KeyPath di Swift?

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.

Sintaks KeyPath

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.

swift
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.

Hierarki KeyPath: WritableKeyPath dan ReferenceWritableKeyPath

KeyPath memiliki hierarki subtipe yang mencerminkan tingkat akses ke properti. Hierarki dasar: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Setiap subtipe menambahkan kemampuan.

Tingkat akses KeyPath

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.

TipeAksesTipe objekPerubahan
KeyPathReadOnlyApapunTidak
WritableKeyPathReadWriteTipe nilai (inout)Melalui konteks mutating
ReferenceWritableKeyPathReadWriteTipe referensiPenugasan langsung
swift
// 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 di Combine dan SwiftUI

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.

Assign di Combine

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.

swift
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 yang dibuat melalui Binding(get:set:) atau proyeksi ($). KeyPath memungkinkan SwiftUI melacak perubahan secara otomatis dan memperbarui UI tanpa usaha berlebihan.

Menggunakan KeyPath untuk mengurutkan dan memfilter

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 generik pengurutan berdasarkan KeyPath

Fungsi sorted menerima KeyPath di mana Value: Comparable. Ini menjamin bahwa properti yang digunakan untuk mengurutkan mendukung perbandingan. Kompiler memeriksa ini pada tahap kompilasi.

swift
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.

Type-erased AnyKeyPath

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.

Penerapan AnyKeyPath

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.

swift
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 yang bertipe selalu lebih disukai. AnyKeyPath adalah alat untuk kasus ketika tipe benar-benar tidak diketahui pada tahap kompilasi, misalnya, saat serialisasi atau refleksi.

Kinerja KeyPath vs kunci teks

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.

Perbandingan kinerja

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.

swift
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

Apa itu KeyPath di Swift dengan kata sederhana?

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.

Apa perbedaan antara KeyPath, WritableKeyPath dan ReferenceWritableKeyPath?

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.

Di mana KeyPath diterapkan di Swift?

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.

Apakah KeyPath lebih aman dari value(forKey:)?

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.

Bisakah KeyPath dibuat secara dinamis?

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

  • KeyPath — jalur bertipe ke properti, direpresentasikan sebagai tipe nilai kelas satu
  • Hierarki KeyPath mencakup WritableKeyPath dan ReferenceWritableKeyPath untuk berbagai tingkat akses
  • Combine dan SwiftUI secara aktif menggunakan KeyPath untuk pengikatan reaktif dan binding
  • Pengurutan dan pemfilteran melalui KeyPath meningkatkan keterbacaan dan keamanan tipe kode
  • AnyKeyPath — varian type-erased untuk menyimpan KeyPath heterogen di koleksi
  • Kinerja KeyPath 10-20 kali lebih tinggi dari value(forKey:)

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.

Diskusikan proyek

Baca juga