KeyPath: klíčové pojmy a typovaný přístup

Autor: IT Sectr Publikováno: 2026-06-18 Doba čtení: 10 min

KeyPath — je typovaná cesta k vlastnosti objektu ve Swiftu, reprezentovaná jako hodnota první třídy. Na rozdíl od textových klíčů v KVC (Key-Value Coding), KeyPath je kontrolován kompilátorem ve fázi kompilace: kompilátor zná typ kořenového objektu, typ vlastnosti a může zaručit, že cesta existuje. KeyPath se používá v Combine pro reaktivní vázání, ve SwiftUI pro obousměrné bindování a ve standardní knihovně pro řazení a filtrování kolekcí. Podle Apple Developer, 2025 je KeyPath základním stavebním blokem pro funkcionální programování ve Swiftu.

Hlavní body

  • KeyPath — typovaná cesta k vlastnosti, kontrolovaná kompilátorem
  • WritableKeyPath — podtyp KeyPath pro vlastnosti s přístupem pro zápis
  • ReferenceWritableKeyPath — pro měnitelné vlastnosti referenčních typů
  • Combine používá KeyPath k vázání vydavatelů k vlastnostem objektů
  • AnyKeyPath — type-erased varianta pro ukládání KeyPath v kolekcích

Co je KeyPath ve Swiftu?

KeyPath — je typ ze standardní knihovny Swift, který představuje cestu k vlastnosti objektu. Na rozdíl od ručního přístupu k vlastnosti přes tečku (object.property) nebo textového klíče (value(forKey:)), KeyPath je objekt první třídy: lze jej předat jako argument, uložit do proměnné a kombinovat.

Syntaxe KeyPath

KeyPath se zapisuje pomocí zpětného lomítka a cesty k vlastnosti: \Person.name. Cesta může být vnořená: \Person.address.city. Kompilátor kontroluje, že Person má vlastnost name a že name je skutečně typu String. Pokud vlastnost neexistuje nebo je typ nesprávný, kód se nezkompiluje.

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

// KeyPath (pouze pro čtení)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]

Přístup k vlastnosti přes KeyPath se provádí pomocí subscriptu object[keyPath: path]. Pro vlastnosti ReadOnly se používá KeyPath. Pokud je vlastnost měnitelná (var), je k dispozici WritableKeyPath. Pro referenční typy — ReferenceWritableKeyPath, umožňující změnu vlastnosti přes samotný KeyPath.

Hierarchie KeyPath: WritableKeyPath a ReferenceWritableKeyPath

KeyPath má hierarchii podtypů odrážející úroveň přístupu k vlastnosti. Základní hierarchie: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Každý podtyp přidává možnosti.

Úrovně přístupu KeyPath

KeyPath — pouze pro čtení. WritableKeyPath — čtení a zápis pro hodnotové typy (struct). ReferenceWritableKeyPath — čtení a zápis pro referenční typy (class). Swift automaticky vybírá správný podtyp na základě kontextu.

TypPřístupTyp objektuZměna
KeyPathReadOnlyLibovolnýNe
WritableKeyPathReadWriteHodnotový typ (inout)Přes mutating kontext
ReferenceWritableKeyPathReadWriteReferenční typPřímé přiřazení
swift
// WritableKeyPath pro hodnotový typ
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true

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

Důležitý rozdíl: pro hodnotové typy vyžaduje nastavení přes KeyPath var (kontext inout), zatímco pro referenční typy — měnitelnou vlastnost. To odpovídá obecné sémantice Swiftu: hodnotové typy se předávají hodnotou, takže změna vyžaduje mutovatelnost kontejneru.

KeyPath v Combine a SwiftUI

KeyPath hraje centrální roli v Combine a SwiftUI. V Combine operátor assign používá KeyPath k vázání hodnoty vydavatele k vlastnosti objektu. Ve SwiftUI Binding používá KeyPath k obousměrnému propojení modelu a zobrazení.

Assign v Combine

Operátor assign(to:on:) přijímá ReferenceWritableKeyPath a objekt. Když vydavatel odešle hodnotu, je automaticky zapsána do zadané vlastnosti. Toto je deklarativní způsob správy stavu bez ručních přiřazení.

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

Ve SwiftUI @Binding používá KeyPath k propojení nadřazeného a podřízeného View. Rodič předává Binding vytvořený přes Binding(get:set:) nebo projekci ($). KeyPath umožňuje SwiftUI automaticky sledovat změny a aktualizovat UI bez zbytečné námahy.

Použití KeyPath pro řazení a filtrování

KeyPath umožňuje psát flexibilní a typově bezpečné funkce řazení a filtrování. Místo předávání uzávěru pokaždé můžete předat KeyPath k vlastnosti, podle které chcete kolekci seřadit. To činí kód čistším a snižuje duplicitu.

Generická funkce řazení podle KeyPath

Funkce sorted přijímá KeyPath kde Value: Comparable. To zaručuje, že vlastnost, podle které řadíme, podporuje porovnání. Kompilátor to kontroluje ve fázi kompilace.

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)

Taková implementace řadí podle libovolné Comparable vlastnosti bez psaní uzávěrů. Pro řazení podle příjmení stačí změnit KeyPath: \Person.lastName. Pokud je třeba řadit podle vlastního klíče (např. délka jména), používá se map uvnitř — vývojář může stále napsat vlastní uzávěr pro nestandardní případy.

Type-erased AnyKeyPath

AnyKeyPath — je základní typ v hierarchii KeyPath, který maže informace o konkrétních typech kořene a hodnoty. AnyKeyPath neví, na jakém typu objektu je volán a jaký typ hodnoty vrací. To je užitečné pro ukládání heterogenních KeyPath v kolekcích a pro reflexi.

Použití AnyKeyPath

AnyKeyPath se používá, když potřebujete uložit seznam cest k různým vlastnostem různých typů. Například v konfigurátoru UI, kde každá cesta konfiguruje určitou vlastnost a typy vlastností se mohou lišit. AnyKeyPath umožňuje jednotnou práci se všemi cestami.

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 { }
// Umožňuje konfigurovat vlastnosti přes AnyKeyPath

AnyKeyPath vyžaduje konverzi typů při získávání hodnoty, protože konkrétní typ je smazán. Pro úplnou typovou bezpečnost je vždy preferován typovaný KeyPath. AnyKeyPath je nástroj pro případy, kdy typy jsou skutečně neznámé ve fázi kompilace, například při serializaci nebo reflexi.

Výkon KeyPath vs textové klíče

KeyPath je výrazně výkonnější než textové klíče KVC (value(forKey:)). Textové klíče jsou vypočítávány pomocí runtime mechanismu Objective-C, včetně parsování textu, vyhledávání v runtime a konverze typů. KeyPath je statický mechanismus založený na nativních strukturách Swift.

Srovnání výkonu

Podle testů je KeyPath v průměru 10-20krát rychlejší než value(forKey:) pro přístup k vlastnostem. Rozdíl je způsoben absencí vyhledávání v runtime a dynamického dispatchování. KeyPath přímo přistupuje k offsetu vlastnosti v paměti při dostatečné optimalizaci kompilátoru.

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

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

KVC je nejen pomalejší, ale také nebezpečný z hlediska typů: text „name“ nemusí existovat a konverze as! String může selhat. KeyPath zaručuje existenci vlastnosti a správnost typu ve fázi kompilace. Pro kritická místa z hlediska výkonu (animace, seznamy tisíců prvků) je KeyPath jedinou správnou volbou.

Často kladené otázky

Co je KeyPath ve Swiftu jednoduše řečeno?

KeyPath — je ukazatel na vlastnost objektu, který lze předat jako běžnou hodnotu. Místo psaní person.name vytvoříte cestu \Person.name a použijete ji ke čtení nebo zápisu vlastnosti v libovolné instanci Person.

Jaký je rozdíl mezi KeyPath, WritableKeyPath a ReferenceWritableKeyPath?

KeyPath — pouze pro čtení. WritableKeyPath — pro čtení a zápis hodnotových typů (struct) pomocí inout kontextu. ReferenceWritableKeyPath — pro čtení a zápis referenčních typů (class) bez dalších podmínek.

Kde se KeyPath ve Swiftu používá?

KeyPath je široce používán v Combine (assign(to:on:)), SwiftUI (Binding, FocusState), řazení kolekcí (sorted(by:)), Core Data (NSSortDescriptor) a pro bezpečný přístup k vnořeným vlastnostem.

Je KeyPath bezpečnější než value(forKey:)?

Ano, KeyPath je plně typově bezpečný. Chyba v cestě (překlep, nesprávný typ) je detekována ve fázi kompilace, nikoli za běhu. value(forKey:) používá texty a může selhat s NSUndefinedKeyException, pokud klíč neexistuje.

Lze KeyPath vytvořit dynamicky?

Přímo — ne, Swift nepodporuje dynamické vytváření KeyPath z textu. Můžete však použít AnyKeyPath pro ukládání a předávání staticky získaných KeyPath. Pro dynamický přístup k vlastnostem pomocí textu použijte value(forKey:) s Objective-C runtime.

Shrnutí

  • KeyPath — typovaná cesta k vlastnosti, reprezentovaná jako hodnotový typ první třídy
  • Hierarchie KeyPath zahrnuje WritableKeyPath a ReferenceWritableKeyPath pro různé úrovně přístupu
  • Combine a SwiftUI aktivně používají KeyPath pro reaktivní vázání a bindování
  • Řazení a filtrování přes KeyPath zvyšuje čitelnost a typovou bezpečnost kódu
  • AnyKeyPath — type-erased varianta pro ukládání heterogenních KeyPath v kolekcích
  • Výkon KeyPath je 10-20krát vyšší než value(forKey:)

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také