KeyPath — ay isang na-type na landas patungo sa property ng isang bagay sa Swift, na kinakatawan bilang isang first-class na halaga. Hindi tulad ng mga text key sa KVC (Key-Value Coding), ang KeyPath ay sinusuri ng compiler sa yugto ng kompilasyon: alam ng compiler ang uri ng root object, ang uri ng property mismo at maaaring garantiya na ang landas ay umiiral. Ang KeyPath ay ginagamit sa Combine para sa reaktibong pagbubuklod, sa SwiftUI para sa two-way na binding at sa standard library para sa pag-uuri at pag-filter ng mga koleksyon. Ayon sa Apple Developer, 2025, ang KeyPath ay isang pangunahing bloke ng gusali para sa functional programming sa Swift.
Mga Pangunahing Punto
KeyPath — ay isang uri mula sa standard library ng Swift na kumakatawan sa isang landas patungo sa property ng isang bagay. Hindi tulad ng manu-manong pag-access sa property sa pamamagitan ng tuldok (object.property) o text key (value(forKey:)), ang KeyPath ay isang first-class na bagay: maaari itong ipasa bilang argumento, iimbak sa isang variable, at pagsamahin.
Ang KeyPath ay isinusulat sa pamamagitan ng backslash at landas patungo sa property: \Person.name. Ang landas ay maaaring nested: \Person.address.city. Sinusuri ng compiler na ang Person ay may property na name at ang name ay talagang uri ng String. Kung ang property ay hindi umiiral o ang uri ay mali, ang code ay hindi nagko-compile.
struct Person: Codable {
let name: String
let age: Int
var isActive: Bool
}
// KeyPath (basa lamang)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]
Ang pag-access sa property sa pamamagitan ng KeyPath ay ginagawa sa pamamagitan ng subscript object[keyPath: path]. Para sa ReadOnly na mga property, ginagamit ang KeyPath. Kung ang property ay nababago (var), available ang WritableKeyPath. Para sa mga reference type — ReferenceWritableKeyPath, na nagpapahintulot sa pagbabago ng property sa pamamagitan ng KeyPath mismo.
KeyPath ay may hierarkiya ng mga subtype na sumasalamin sa antas ng pag-access sa property. Ang pangunahing hierarkiya: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Bawat subtype ay nagdaragdag ng mga kakayahan.
KeyPath — basa lamang. WritableKeyPath — basa at sulat para sa value type (struct). ReferenceWritableKeyPath — basa at sulat para sa reference type (class). Awtomatikong pinipili ng Swift ang tamang subtype batay sa konteksto.
| Uri | Access | Uri ng bagay | Pagbabago |
|---|---|---|---|
| KeyPath | ReadOnly | Kahit ano | Hindi |
| WritableKeyPath | ReadWrite | Value type (inout) | Sa pamamagitan ng mutating context |
| ReferenceWritableKeyPath | ReadWrite | Reference type | Direktang pagtatalaga |
// WritableKeyPath para sa value type
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true
// ReferenceWritableKeyPath para sa klase
class User: NSObject {
@objc dynamic var name: String = ""
}
let user = User()
let refPath: ReferenceWritableKeyPath<User, String> = \User.name
user[keyPath: refPath] = "Charlie"
Mahalagang pagkakaiba: para sa value type, ang pagtatakda sa pamamagitan ng KeyPath ay nangangailangan ng var (inout context), at para sa reference type — nababagong property. Ito ay tumutugma sa pangkalahatang semantika ng Swift: ang value type ay ipinapasa ayon sa halaga, kaya ang pagbabago ay nangangailangan ng mutability ng container.
KeyPath ay gumaganap ng sentral na papel sa Combine at SwiftUI. Sa Combine, ang operator na assign ay gumagamit ng KeyPath para magbigkis ng halaga ng publisher sa property ng isang bagay. Sa SwiftUI, ang Binding ay gumagamit ng KeyPath para sa two-way na pagbubuklod ng modelo at view.
Ang operator na assign(to:on:) ay tumatanggap ng ReferenceWritableKeyPath at isang bagay. Kapag ang publisher ay nagpadala ng halaga, ito ay awtomatikong isinusulat sa tinukoy na property. Ito ay isang deklaratibong paraan ng pamamahala ng estado nang walang manu-manong pagtatalaga.
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)
}
}
Sa SwiftUI, ang @Binding ay gumagamit ng KeyPath para ikonekta ang parent at child View. Ang parent ay nagpapasa ng Binding
KeyPath ay nagpapahintulot sa pagsulat ng nababaluktot at type-safe na mga function ng pag-uuri at pag-filter. Sa halip na magpasa ng closure sa bawat pagkakataon, maaari kang magpasa ng KeyPath sa property kung saan mo gustong pag-uri-uriin ang koleksyon. Ito ay nagpapalinis ng code at nagbabawas ng pagdoble.
Ang function na 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)
Ang ganitong implementasyon ay nag-uuri ayon sa anumang Comparable na property nang hindi nagsusulat ng mga closure. Para sa pag-uuri ayon sa apelyido, sapat na baguhin ang KeyPath: \Person.lastName. Kung kailangang mag-uri ayon sa custom na key (hal. haba ng pangalan), ginagamit ang map sa loob — ang developer ay maaari pa ring sumulat ng sariling closure para sa mga hindi karaniwang kaso.
AnyKeyPath — ay ang batayang uri sa hierarkiya ng KeyPath na nagbubura ng impormasyon tungkol sa mga tiyak na uri ng root at halaga. Hindi alam ng AnyKeyPath kung sa anong uri ng bagay ito tinatawag at kung anong uri ng halaga ang ibinabalik nito. Ito ay kapaki-pakinabang para sa pag-iimbak ng mga heterogenous na KeyPath sa mga koleksyon at para sa reflection.
Ang AnyKeyPath ay ginagamit kapag kailangan mong mag-imbak ng listahan ng mga landas patungo sa iba't ibang property ng iba't ibang uri. Halimbawa, sa isang UI configurator, kung saan ang bawat landas ay nagko-configure ng isang partikular na property, at ang mga uri ng property ay maaaring magkaiba. Pinapayagan ng AnyKeyPath ang pare-parehong pagtatrabaho sa lahat ng mga landas.
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 { }
// Nagbibigay-daan sa pag-configure ng mga property sa pamamagitan ng AnyKeyPath
Ang AnyKeyPath ay nangangailangan ng type conversion kapag kumukuha ng halaga, dahil ang tiyak na uri ay nabura. Para sa kumpletong kaligtasan ng uri, ang naka-type na KeyPath
KeyPath ay makabuluhang mas mahusay kaysa sa text key ng KVC (value(forKey:)). Ang mga text key ay kinakalkula sa pamamagitan ng Objective-C runtime mechanism, kasama ang pag-parse ng text, paghahanap sa runtime at type conversion. Ang KeyPath ay isang static na mekanismo batay sa native na Swift structures.
Ayon sa mga pagsubok, ang KeyPath ay average na 10-20 beses mas mabilis kaysa sa value(forKey:) para sa pag-access ng property. Ang pagkakaiba ay dahil sa kawalan ng runtime na paghahanap at dynamic na dispatch. Direktang ina-access ng KeyPath ang offset ng property sa memorya na may sapat na optimisasyon ng compiler.
func readWithKeyPath(person: Person) -> String {
person[keyPath: \Person.name]
}
func readWithKVC(person: Person) -> String {
person.value(forKey: "name") as! String
}
Ang KVC ay hindi lamang mas mabagal, kundi hindi ligtas sa mga tuntunin ng uri: ang tekstong “name” ay maaaring hindi umiiral, at ang conversion na as! String ay maaaring mabigo. Ginagarantiya ng KeyPath ang pagkakaroon ng property at kawastuhan ng uri sa yugto ng kompilasyon. Para sa mga kritikal na bahagi sa pagganap (animasyon, listahan ng libu-libong elemento), ang KeyPath ay ang tanging tamang pagpipilian.
Mga Madalas Itanong
KeyPath — ay isang pointer sa property ng isang bagay na maaaring ipasa tulad ng isang ordinaryong halaga. Sa halip na magsulat ng person.name, gumawa ka ng landas na \Person.name at gamitin ito para basahin o isulat ang property sa anumang instance ng Person.
KeyPath — basa lamang. WritableKeyPath — para sa pagbasa at pagsulat ng value type (struct) sa pamamagitan ng inout context. ReferenceWritableKeyPath — para sa pagbasa at pagsulat ng reference type (class) nang walang karagdagang kondisyon.
Ang KeyPath ay malawakang ginagamit sa Combine (assign(to:on:)), SwiftUI (Binding, FocusState), pag-uuri ng koleksyon (sorted(by:)), Core Data (NSSortDescriptor) at para sa ligtas na pag-access sa mga nested na property.
Oo, ang KeyPath ay ganap na type-safe. Ang error sa landas (maling type, maling uri) ay natutukoy sa yugto ng kompilasyon, hindi sa runtime. Ang value(forKey:) ay gumagamit ng teksto at maaaring mabigo sa NSUndefinedKeyException kung ang key ay hindi umiiral.
Direkta — hindi, hindi sinusuportahan ng Swift ang dinamikong paglikha ng KeyPath mula sa teksto. Gayunpaman, maaari mong gamitin ang AnyKeyPath para sa pag-iimbak at pagpapasa ng mga KeyPath na nakuha nang statically. Para sa dinamikong pag-access sa mga property sa pamamagitan ng teksto, gamitin ang value(forKey:) na may Objective-C runtime.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din