KeyPath: kernconcepten en getypeerde toegang

Auteur: IT Sectr Gepubliceerd: 2026-06-18 Leestijd: 10 min

KeyPath — is een getypeerd pad naar een eigenschap van een object in Swift, weergegeven als een eersteklas waarde. In tegenstelling tot tekst sleutels in KVC (Key-Value Coding), wordt KeyPath gecontroleerd door de compiler tijdens de compilatiefase: de compiler kent het type van het root-object, het type van de eigenschap en kan garanderen dat het pad bestaat. KeyPath wordt gebruikt in Combine voor reactieve binding, in SwiftUI voor tweerichtingsbinding en in de standaardbibliotheek voor het sorteren en filteren van collecties. Volgens Apple Developer, 2025 is KeyPath een fundamenteel bouwblok voor functioneel programmeren in Swift.

Belangrijkste punten

  • KeyPath — getypeerd pad naar eigenschap, gecontroleerd door de compiler
  • WritableKeyPath — subtype van KeyPath voor eigenschappen met schrijftoegang
  • ReferenceWritableKeyPath — voor wijzigbare eigenschappen van referentietypes
  • Combine gebruikt KeyPath om uitgevers te binden aan eigenschappen van objecten
  • AnyKeyPath — type-erased variant voor het opslaan van KeyPath in collecties

Wat is KeyPath in Swift?

KeyPath — is een type uit de Swift-standaardbibliotheek dat een pad naar een eigenschap van een object vertegenwoordigt. In tegenstelling tot handmatige toegang tot een eigenschap via een punt (object.property) of een tekst sleutel (value(forKey:)), is KeyPath een eersteklas object: het kan worden doorgegeven als argument, opgeslagen in een variabele en worden gecombineerd.

Syntaxis van KeyPath

KeyPath wordt geschreven met een backslash en het pad naar de eigenschap: \Person.name. Het pad kan genest zijn: \Person.address.city. De compiler controleert dat Person een eigenschap name heeft en dat name daadwerkelijk van het type String is. Als de eigenschap niet bestaat of het type onjuist is, wordt de code niet gecompileerd.

swift
struct Person: Codable {
    let name: String
    let age: Int
    var isActive: Bool
}

// KeyPath (alleen lezen)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]

Toegang tot een eigenschap via KeyPath gebeurt via de subscript object[keyPath: path]. Voor ReadOnly-eigenschappen wordt KeyPath gebruikt. Als de eigenschap wijzigbaar is (var), is WritableKeyPath beschikbaar. Voor referentietypes — ReferenceWritableKeyPath, waarmee de eigenschap via de KeyPath zelf kan worden gewijzigd.

Hiërarchie van KeyPath: WritableKeyPath en ReferenceWritableKeyPath

KeyPath heeft een hiërarchie van subtypes die het toegangsniveau tot de eigenschap weerspiegelt. De basis hiërarchie: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Elk subtype voegt mogelijkheden toe.

Toegangsniveaus van KeyPath

KeyPath — alleen lezen. WritableKeyPath — lezen en schrijven voor waardetypes (struct). ReferenceWritableKeyPath — lezen en schrijven voor referentietypes (class). Swift kiest automatisch het juiste subtype op basis van de context.

TypeToegangObjecttypeWijziging
KeyPathReadOnlyElkNee
WritableKeyPathReadWriteWaardetype (inout)Via mutating context
ReferenceWritableKeyPathReadWriteReferentietypeDirecte toewijzing
swift
// WritableKeyPath voor waardetype
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true

// ReferenceWritableKeyPath voor klasse
class User: NSObject {
    @objc dynamic var name: String = ""
}
let user = User()
let refPath: ReferenceWritableKeyPath<User, String> = \User.name
user[keyPath: refPath] = "Charlie"

Belangrijk verschil: voor waardetypes vereist instellen via KeyPath var (inout-context), en voor referentietypes — een wijzigbare eigenschap. Dit komt overeen met de algemene semantiek van Swift: waardetypes worden op waarde doorgegeven, dus wijziging vereist mutabiliteit van de container.

KeyPath in Combine en SwiftUI

KeyPath speelt een centrale rol in Combine en SwiftUI. In Combine gebruikt de operator assign KeyPath om de waarde van een uitgever aan een eigenschap van een object te binden. In SwiftUI gebruikt Binding KeyPath voor tweerichtingsbinding van model en weergave.

Assign in Combine

De operator assign(to:on:) accepteert een ReferenceWritableKeyPath en een object. Wanneer de uitgever een waarde verzendt, wordt deze automatisch naar de opgegeven eigenschap geschreven. Dit is een declaratieve manier om status te beheren zonder handmatige toewijzingen.

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)
    }
}

In SwiftUI gebruikt @Binding KeyPath om de bovenliggende en onderliggende View te verbinden. De ouder geeft een Binding door, gemaakt via Binding(get:set:) of projectie ($). KeyPath stelt SwiftUI in staat om automatisch wijzigingen te volgen en de UI bij te werken zonder overbodige inspanning.

KeyPath gebruiken voor sorteren en filteren

KeyPath maakt het mogelijk flexibele en typeveilige sorteer- en filterfuncties te schrijven. In plaats van telkens een closure door te geven, kunt u een KeyPath naar de eigenschap doorgeven waarop u de collectie wilt sorteren. Dit maakt de code schoner en vermindert duplicatie.

Generieke sorteerfunctie op KeyPath

De functie sorted accepteert KeyPath waar Value: Comparable. Dit garandeert dat de eigenschap waarop we sorteren vergelijking ondersteunt. De compiler controleert dit tijdens de compilatiefase.

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)

Een dergelijke implementatie sorteert op elke Comparable-eigenschap zonder closures te schrijven. Voor sorteren op achternaam volstaat het om KeyPath te wijzigen: \Person.lastName. Als u op een aangepaste sleutel moet sorteren (bijv. lengte van de naam), wordt map binnenin gebruikt — de ontwikkelaar kan nog steeds zijn eigen closure schrijven voor niet-standaard gevallen.

Type-erased AnyKeyPath

AnyKeyPath — is het basistype in de KeyPath hiërarchie dat informatie over de specifieke typen van de root en waarde wist. AnyKeyPath weet niet op welk objecttype het wordt aangeroepen en welk waardetype het retourneert. Dit is handig voor het opslaan van heterogene KeyPaths in collecties en voor reflectie.

Toepassing van AnyKeyPath

AnyKeyPath wordt gebruikt wanneer u een lijst met paden naar verschillende eigenschappen van verschillende typen moet opslaan. Bijvoorbeeld in een UI-configurator, waar elk pad een specifieke eigenschap configureert en de eigenschapstypen kunnen verschillen. AnyKeyPath maakt uniform werken met alle paden mogelijk.

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 { }
// Maakt het configureren van eigenschappen via AnyKeyPath mogelijk

AnyKeyPath vereist typeconversie bij het ophalen van de waarde, omdat het specifieke type is gewist. Voor volledige typeveiligheid heeft getypeerd KeyPath altijd de voorkeur. AnyKeyPath is een hulpmiddel voor gevallen waarin typen echt onbekend zijn tijdens de compilatie, zoals bij serialisatie of reflectie.

Prestaties KeyPath vs tekst sleutels

KeyPath is aanzienlijk performanter dan tekst sleutels van KVC (value(forKey:)). Tekst sleutels worden berekend via het runtime-mechanisme van Objective-C, inclusief het parseren van tekst, zoeken in runtime en typeconversie. KeyPath is een statisch mechanisme gebaseerd op native Swift-structuren.

Prestatievergelijking

Volgens tests is KeyPath gemiddeld 10-20 keer sneller dan value(forKey:) voor toegang tot eigenschappen. Het verschil is te wijten aan het ontbreken van runtime-zoekopdracht en dynamische dispatch. KeyPath heeft rechtstreeks toegang tot de offset van de eigenschap in het geheugen met voldoende optimalisatie van de compiler.

swift
func readWithKeyPath(person: Person) -> String {
    person[keyPath: \Person.name]
}

func readWithKVC(person: Person) -> String {
    person.value(forKey: "name") as! String
}

KVC is niet alleen langzamer, maar ook onveilig wat betreft typen: de tekst „name“ bestaat mogelijk niet en de conversie as! String kan mislukken. KeyPath garandeert het bestaan van de eigenschap en de juistheid van het type tijdens de compilatie. Voor prestatiekritieke delen (animaties, lijsten met duizenden elementen) is KeyPath de enige juiste keuze.

Veelgestelde vragen

Wat is KeyPath in Swift in eenvoudige woorden?

KeyPath — is een verwijzing naar een eigenschap van een object die kan worden doorgegeven als een gewone waarde. In plaats van person.name te schrijven, maakt u het pad \Person.name en gebruikt u het om de eigenschap in elk exemplaar van Person te lezen of te schrijven.

Wat is het verschil tussen KeyPath, WritableKeyPath en ReferenceWritableKeyPath?

KeyPath — alleen lezen. WritableKeyPath — voor lezen en schrijven van waardetypes (struct) via inout-context. ReferenceWritableKeyPath — voor lezen en schrijven van referentietypes (class) zonder extra voorwaarden.

Waar wordt KeyPath toegepast in Swift?

KeyPath wordt veel gebruikt in Combine (assign(to:on:)), SwiftUI (Binding, FocusState), het sorteren van collecties (sorted(by:)), Core Data (NSSortDescriptor) en voor veilige toegang tot geneste eigenschappen.

Is KeyPath veiliger dan value(forKey:)?

Ja, KeyPath is volledig typeveilig. Een fout in het pad (typefout, onjuist type) wordt gedetecteerd tijdens de compilatie, niet in runtime. value(forKey:) gebruikt tekst en kan mislukken met NSUndefinedKeyException als de sleutel niet bestaat.

Kan KeyPath dynamisch worden gemaakt?

Direct — nee, Swift ondersteunt geen dynamische creatie van KeyPath uit tekst. U kunt echter AnyKeyPath gebruiken voor het opslaan en doorgeven van statisch verkregen KeyPaths. Voor dynamische toegang tot eigenschappen via tekst gebruikt u value(forKey:) met Objective-C runtime.

Samenvatting

  • KeyPath — getypeerd pad naar eigenschap, weergegeven als een eersteklas waardetype
  • Hiërarchie KeyPath omvat WritableKeyPath en ReferenceWritableKeyPath voor verschillende toegangsniveaus
  • Combine en SwiftUI gebruiken actief KeyPath voor reactieve bindingen
  • Sorteren en filteren via KeyPath verhoogt de leesbaarheid en typeveiligheid van code
  • AnyKeyPath — type-erased variant voor het opslaan van heterogene KeyPaths in collecties
  • Prestaties KeyPath is 10-20 keer hoger dan value(forKey:)

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook