KeyPath — Swift-də obyektin xassəsinə tipli yoldur, birinci dərəcəli dəyər kimi təqdim olunur. KVC-dəki (Key-Value Coding) sətir açarlarından fərqli olaraq, KeyPath kompilyator tərəfindən yığma mərhələsində yoxlanılır: kompilyator kök obyektin tipini, xassənin tipini bilir və yolun mövcud olduğuna zəmanət verə bilər. KeyPath Combine-də reaktiv bağlama, SwiftUI-də ikitərəfli bindiq və standart kitabxanada kolleksiyaların sıralanması və filtrlənməsi üçün istifadə olunur. Apple Developer, 2025-ə görə, KeyPath Swift-də funksional proqramlaşdırma üçün fundamental tikinti blokudur.
Əsas məqamlar
KeyPath — Swift standart kitabxanasından olan tip, obyektin xassəsinə yolu təmsil edir. Xassəyə nöqtə vasitəsilə əl ilə girişdən (object.property) və ya sətir açarından (value(forKey:)) fərqli olaraq, KeyPath birinci dərəcəli obyektdir: onu arqument kimi ötürmək, dəyişəndə saxlamaq və birləşdirmək olar.
KeyPath tərs işarə və xassəyə yol vasitəsilə yazılır: \Person.name. Yol iç-içə ola bilər: \Person.address.city. Kompilyator Person-un name xassəsinə malik olduğunu və name-in həqiqətən String tipində olduğunu yoxlayır. Xassə mövcud deyilsə və ya tip səhvdirsə, kod kompilyasiya olunmur.
struct Person: Codable {
let name: String
let age: Int
var isActive: Bool
}
// KeyPath (yalnız oxumaq üçün)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]
KeyPath vasitəsilə xassəyə giriş object[keyPath: path] subskripti ilə həyata keçirilir. ReadOnly xassələri üçün KeyPath istifadə olunur. Xassə dəyişkəndirsə (var), WritableKeyPath mövcuddur. İstinad tipləri üçün — ReferenceWritableKeyPath, KeyPath vasitəsilə xassəni dəyişməyə imkan verir.
KeyPath xassəyə giriş səviyyəsini əks etdirən alt tiplər iyerarxiyasına malikdir. Əsas iyerarxiya: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath. Hər alt tip imkanlar əlavə edir.
KeyPath — yalnız oxumaq. WritableKeyPath — dəyər tipləri (struct) üçün oxumaq və yazmaq. ReferenceWritableKeyPath — istinad tipləri (class) üçün oxumaq və yazmaq. Swift kontekstdən asılı olaraq avtomatik olaraq düzgün alt tipi seçir.
| Tip | Giriş | Obyektin tipi | Dəyişmə |
|---|---|---|---|
| KeyPath | ReadOnly | İstənilən | Xeyr |
| WritableKeyPath | ReadWrite | Value-tipi (inout) | Mutating konteksti ilə |
| ReferenceWritableKeyPath | ReadWrite | Reference-tipi | Birbaşa təyin etmə |
// WritableKeyPath dəyər tipi üçün
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true
// ReferenceWritableKeyPath class üçün
class User: NSObject {
@objc dynamic var name: String = ""
}
let user = User()
let refPath: ReferenceWritableKeyPath<User, String> = \User.name
user[keyPath: refPath] = "Charlie"
Vacib fərq: dəyər tipləri üçün KeyPath vasitəsilə təyin etmə var (inout konteksti) tələb edir, istinad tipləri üçün isə dəyişkən xassə. Bu Swift-in ümumi semantikasına uyğundur: dəyər tipləri dəyərlə ötürülür, buna görə dəyişiklik konteynerin mutasiyasını tələb edir.
KeyPath Combine və SwiftUI-də mərkəzi rol oynayır. Combine-də assign operatoru naşirin dəyərini obyektin xassəsinə bağlamaq üçün KeyPath istifadə edir. SwiftUI-də Binding model və görünüşün ikitərəfli əlaqələndirilməsi üçün KeyPath istifadə edir.
assign(to:on:) operatoru ReferenceWritableKeyPath və obyekt qəbul edir. Naşir dəyər göndərdikdə, avtomatik olaraq göstərilən xassəyə yazılır. Bu, əl ilə təyin etmədən vəziyyətin idarə edilməsinin deklarativ üsuludur.
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)
}
}
SwiftUI-də @Binding ana və uşaq View-i birləşdirmək üçün KeyPath istifadə edir. Ana Binding(get:set:) və ya proyeksiya ($) vasitəsilə yaradılmış Binding
KeyPath çevik və tip təhlükəsiz sıralama və filtrasiya funksiyaları yazmağa imkan verir. Hər dəfə closure ötürmək əvəzinə, kolleksiyanı sıralamaq istədiyiniz xassəyə KeyPath ötürə bilərsiniz. Bu kodu təmizləyir və təkrarlanmanı azaldır.
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)
Belə bir tətbiq closure yazmadan istənilən Comparable xassəsi üzrə sıralayır. Soyad üzrə sıralamaq üçün KeyPath-i dəyişmək kifayətdir: \Person.lastName. Qeyri-standart açar üzrə sıralamaq lazımdırsa (məsələn, adın uzunluğu), daxildə map istifadə olunur — proqramçı qeyri-standart hallar üçün öz closure-nu yaza bilər.
AnyKeyPath — KeyPath iyerarxiyasında əsas tipdir, kök və dəyərin konkret tipləri haqqında məlumatı silir. AnyKeyPath hansı obyekt tipində çağırıldığını və hansı dəyər tipini qaytardığını bilmir. Bu, müxtəlif KeyPath-ləri kolleksiyalarda saxlamaq və refleksiya üçün faydalıdır.
AnyKeyPath müxtəlif tiplərin müxtəlif xassələrinə yolların siyahısını saxlamaq lazım olduqda istifadə olunur. Məsələn, UI konfiquratorunda, hər yol müəyyən bir xassəni konfiqurasiya edir və xassə tipləri fərqlənə bilər. AnyKeyPath bütün yollarla vahid şəkildə işləməyə imkan verir.
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 { }
// AnyKeyPath vasitəsilə xassələri konfiqurasiya etməyə imkan verir
AnyKeyPath dəyəri çıxararkən tip çevirmə tələb edir, çünki konkret tip silinib. Tam tip təhlükəsizliyi üçün həmişə tipli KeyPath
KeyPath KVC-nin (value(forKey:)) sətir açarlarından əhəmiyyətli dərəcədə daha məhsuldardır. Sətir açarları Objective-C runtime mexanizmi vasitəsilə hesablanır, sətrin pars edilməsi, runtimedə axtarış və tip çevirmə daxildir. KeyPath — Swift-in nativ strukturlarına əsaslanan statik mexanizmdir.
Testlərə görə, KeyPath xassələrə girişdə value(forKey:) -dən orta hesabla 10-20 dəfə sürətlidir. Fərq runtime axtarışının və dinamik dispetçerin olmaması ilə bağlıdır. KeyPath kompilyatorun kifayət qədər optimallaşdırılması ilə birbaşa yaddaşdakı xassə offsetinə müraciət edir.
func readWithKeyPath(person: Person) -> String {
person[keyPath: \Person.name]
}
func readWithKVC(person: Person) -> String {
person.value(forKey: "name") as! String
}
KVC nəinki daha yavaş, həm də tipcə təhlükəsiz deyil: “name” sətri mövcud olmaya bilər, as! String çevirməsi isə çökə bilər. KeyPath xassənin mövcudluğuna və tipin düzgünlüyünə kompilyasiya mərhələsində zəmanət verir. Performans baxımından kritik yerlər üçün (animasiyalar, minlərlə elementdən ibarət siyahı) KeyPath yeganə düzgün seçimdir.
Tez-tez verilən suallar
KeyPath — adi dəyər kimi ötürülə bilən obyektin xassəsinə göstəricidir. person.name yazmaq əvəzinə, \Person.name yolunu yaradır və onu istənilən Person nümunəsində xassəni oxumaq və ya yazmaq üçün istifadə edirsiniz.
KeyPath — yalnız oxumaq üçün. WritableKeyPath — dəyər tiplərinin (struct) inout konteksti vasitəsilə oxunması və yazılması üçün. ReferenceWritableKeyPath — əlavə şərtlər olmadan istinad tiplərinin (class) oxunması və yazılması üçün.
KeyPath geniş şəkildə Combine (assign(to:on:)), SwiftUI (Binding, FocusState), kolleksiyaların sıralanması (sorted(by:)), Core Data (NSSortDescriptor) və iç-içə xassələrə təhlükəsiz giriş üçün istifadə olunur.
Bəli, KeyPath tam tip təhlükəsizdir. Yoldakı səhv (səhv yazı, yanlış tip) runtime-da deyil, kompilyasiya mərhələsində aşkar edilir. value(forKey:) sətirlərdən istifadə edir və açar mövcud deyilsə, NSUndefinedKeyException ilə çökə bilər.
Birbaşa — yox, Swift sətirdən dinamik KeyPath yaradılmasını dəstəkləmir. Bununla belə, statik əldə edilmiş KeyPath-ləri saxlamaq və ötürmək üçün AnyKeyPath istifadə edilə bilər. Sətir üzrə xassələrə dinamik giriş üçün Objective-C runtime ilə value(forKey:) istifadə edin.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun