KeyPath Swift میں کسی آبجیکٹ کی خصوصیت کا ایک ٹائپ شدہ راستہ ہے، جسے فرسٹ کلاس ویلیو کے طور پر پیش کیا جاتا ہے۔ KVC (Key-Value Coding) میں سٹرنگ کلیدوں کے برعکس، KeyPath کو کمپائلر بلڈ ٹائم پر چیک کرتا ہے: کمپائلر روٹ آبجیکٹ کی قسم، خصوصیت کی قسم جانتا ہے اور ضمانت دے سکتا ہے کہ راستہ موجود ہے۔ KeyPath کا استعمال Combine میں ری ایکٹو بائنڈنگ کے لیے، SwiftUI میں دو طرفہ بائنڈنگ کے لیے اور معیاری لائبریری میں کلیکشنز کو ترتیب دینے اور فلٹر کرنے کے لیے کیا جاتا ہے۔ Apple Developer، 2025 کے مطابق، KeyPath Swift میں فنکشنل پروگرامنگ کے لیے ایک بنیادی بلاک ہے۔
اہم نکات
KeyPath Swift معیاری لائبریری کی ایک قسم ہے جو کسی آبجیکٹ کی خصوصیت کے راستے کی نمائندگی کرتی ہے۔ ڈوٹ نوٹیشن (object.property) یا سٹرنگ کلید (value(forKey:)) کے ذریعے دستی طور پر خصوصیت تک رسائی کے برعکس، KeyPath ایک فرسٹ کلاس آبجیکٹ ہے: اسے دلیل کے طور پر منتقل کیا جا سکتا ہے، متغیر میں ذخیرہ کیا جا سکتا ہے اور ملایا جا سکتا ہے۔
KeyPath بیک سلیش اور خصوصیت کے راستے کے ساتھ لکھا جاتا ہے: \Person.name۔ راستہ نیسٹڈ ہو سکتا ہے: \Person.address.city۔ کمپائلر تصدیق کرتا ہے کہ Person میں name کی خصوصیت ہے اور name حقیقتاً String ہے۔ اگر خصوصیت موجود نہیں ہے یا قسم غلط ہے، تو کوڈ کمپائل نہیں ہوگا۔
struct Person: Codable {
let name: String
let age: Int
var isActive: Bool
}
// KeyPath (صرف پڑھنا)
let namePath: KeyPath<Person, String> = \Person.name
let person = Person(name: "Alice", age: 30, isActive: true)
let name = person[keyPath: namePath]
KeyPath کے ذریعے خصوصیت تک رسائی سب سکرپٹ object[keyPath: path] کے ذریعے کی جاتی ہے۔ صرف پڑھنے والی خصوصیات کے لیے، KeyPath استعمال کیا جاتا ہے۔ اگر خصوصیت قابل تبدیل (var) ہے، تو WritableKeyPath دستیاب ہے۔ حوالہ اقسام کے لیے، ReferenceWritableKeyPath KeyPath کے ذریعے براہ راست خصوصیت کو تبدیل کرنے کی اجازت دیتا ہے۔
KeyPath کی ایک ذیلی قسم کا درجہ بندی ہے جو خصوصیت تک رسائی کی سطح کو ظاہر کرتی ہے۔ بنیادی درجہ بندی یہ ہے: AnyKeyPath → PartialKeyPath → KeyPath → WritableKeyPath → ReferenceWritableKeyPath۔ ہر ذیلی قسم صلاحیتوں میں اضافہ کرتی ہے۔
KeyPath — صرف پڑھنا۔ WritableKeyPath — ویلیو اقسام (struct) کے لیے پڑھنا اور لکھنا۔ ReferenceWritableKeyPath — حوالہ اقسام (class) کے لیے پڑھنا اور لکھنا۔ Swift سیاق و سباق کی بنیاد پر خود بخود صحیح ذیلی قسم کا انتخاب کرتا ہے۔
| قسم | رسائی | آبجیکٹ کی قسم | تبدیلی |
|---|---|---|---|
| KeyPath | صرف پڑھنا | کوئی بھی | نہیں |
| WritableKeyPath | پڑھنا اور لکھنا | ویلیو قسم (inout) | mutating سیاق و سباق کے ذریعے |
| ReferenceWritableKeyPath | پڑھنا اور لکھنا | حوالہ قسم | براہ راست تفویض |
// WritableKeyPath ویلیو قسم کے لئے
var mutablePerson = Person(name: "Bob", age: 25, isActive: false)
let writablePath: WritableKeyPath<Person, Bool> = \Person.isActive
mutablePerson[keyPath: writablePath] = true
// ReferenceWritableKeyPath کلاس کے لئے
class User: NSObject {
@objc dynamic var name: String = ""
}
let user = User()
let refPath: ReferenceWritableKeyPath<User, String> = \User.name
user[keyPath: refPath] = "Charlie"
ایک اہم فرق: ویلیو اقسام کے لیے، KeyPath کے ذریعے سیٹ کرنے کے لیے var (inout سیاق و سباق) کی ضرورت ہوتی ہے، جبکہ حوالہ اقسام کے لیے صرف ایک قابل تبدیل خصوصیت کافی ہوتی ہے۔ یہ Swift کی عام معنویات کے مطابق ہے: ویلیو اقسام قدر کے طور پر منتقل ہوتی ہیں، لہٰذا تبدیلی کے لیے کنٹینر کی قابل تبدیلی ضروری ہے۔
KeyPath Combine اور SwiftUI میں مرکزی کردار ادا کرتا ہے۔ Combine میں، assign آپریٹر ناشر کی قدر کو آبجیکٹ کی خصوصیت سے باندھنے کے لیے KeyPath استعمال کرتا ہے۔ SwiftUI میں، Binding ماڈل اور ویو کے درمیان دو طرفہ ربط کے لیے KeyPath استعمال کرتا ہے۔
assign(to:on:) آپریٹر ایک ReferenceWritableKeyPath اور ایک آبجیکٹ قبول کرتا ہے۔ جب ناشر قدر جاری کرتا ہے، تو یہ خود بخود مخصوص خصوصیت میں لکھ دی جاتی ہے۔ یہ دستی تفویض کے بغیر حالت کو منظم کرنے کا ایک اعلانیہ طریقہ ہے۔
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 میں، @Binding پیرنٹ اور چائلڈ ویو کو جوڑنے کے لیے KeyPath استعمال کرتا ہے۔ پیرنٹ Binding(get:set:) یا پروجیکشن ($) کے ذریعے بنایا گیا Binding
KeyPath لچکدار اور قسم کے لحاظ سے محفوظ ترتیب اور فلٹرنگ فنکشنز لکھنے کے قابل بناتا ہے۔ ہر بار کلوزر منتقل کرنے کے بجائے، آپ اس خصوصیت کے لیے KeyPath منتقل کر سکتے ہیں جس کے ذریعے آپ کلیکشن کو ترتیب دینا چاہتے ہیں۔ یہ کوڈ کو صاف تر بناتا ہے اور تکرار کو کم کرتا ہے۔
فنکشن 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)
یہ نفاذ کلوزر لکھے بغیر کسی بھی Comparable خصوصیت کے ذریعے ترتیب دیتا ہے۔ کنیت کے ذریعے ترتیب دینے کے لیے، صرف KeyPath تبدیل کریں: \Person.lastName۔ اگر کسٹم کلید (مثلاً، نام کی لمبائی) کے ذریعے ترتیب دینے کی ضرورت ہو، تو اندرونی طور پر map استعمال کیا جاتا ہے — ڈویلپر غیر معیاری صورتوں کے لیے اپنا کلوزر لکھ سکتا ہے۔
AnyKeyPath KeyPath درجہ بندی میں بنیادی قسم ہے جو مخصوص روٹ اور ویلیو اقسام کے بارے میں معلومات مٹا دیتی ہے۔ AnyKeyPath یہ نہیں جانتا کہ اسے کس آبجیکٹ قسم پر بلایا گیا ہے یا یہ کس ویلیو قسم کو لوٹاتا ہے۔ یہ کلیکشنز میں متنوع KeyPath ذخیرہ کرنے اور ریفلیکشن کے لیے مفید ہے۔
AnyKeyPath اس وقت استعمال ہوتا ہے جب آپ کو مختلف اقسام کی مختلف خصوصیات کے راستوں کی فہرست ذخیرہ کرنے کی ضرورت ہوتی ہے۔ مثال کے طور پر، UI کنفیگریٹر میں، جہاں ہر راستہ ایک مخصوص خصوصیت کو کنفیگر کرتا ہے، اور خصوصیت کی اقسام مختلف ہو سکتی ہیں۔ AnyKeyPath تمام راستوں کے ساتھ یکساں طور پر کام کرنے کی اجازت دیتا ہے۔
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 کے ذریعے خصوصیات ترتیب دےنے کی اجازت دیتا ہے
AnyKeyPath کو قدر حاصل کرتے وقت قسم کی تبدیلی کی ضرورت ہوتی ہے، کیونکہ مخصوص قسم مٹا دی گئی ہے۔ مکمل قسم کی حفاظت کے لیے، ٹائپ شدہ KeyPath
KeyPath KVC سٹرنگ کلیدوں (value(forKey:)) کے مقابلے میں نمایاں طور پر زیادہ موثر ہے۔ سٹرنگ کلیدوں کو Objective-C رن ٹائم میکانزم کے ذریعے حل کیا جاتا ہے، جس میں سٹرنگ پارسنگ، رن ٹائم لوک اپ اور قسم کی تبدیلی شامل ہے۔ KeyPath ایک جامد میکانزم ہے جو مقامی Swift ڈھانچوں پر مبنی ہے۔
بینچ مارکس کے مطابق، خصوصیات تک رسائی کے لیے KeyPath اوسطاً value(forKey:) سے 10-20 گنا تیز ہے۔ فرق رن ٹائم لوک اپ اور ڈائنامک ڈسپیچ کی عدم موجودگی کی وجہ سے ہے۔ KeyPath کافی کمپائلر آپٹیمائزیشن کے ساتھ براہ راست میموری میں خصوصیت کے آفسیٹ تک رسائی حاصل کرتا ہے۔
func readWithKeyPath(person: Person) -> String {
person[keyPath: \Person.name]
}
func readWithKVC(person: Person) -> String {
person.value(forKey: "name") as! String
}
KVC نہ صرف سست ہے، بلکہ قسم کے لحاظ سے غیر محفوظ بھی ہے: سٹرنگ “name” موجود نہیں ہو سکتی اور as! String کاسٹ کریش کر سکتی ہے۔ KeyPath کمپائل ٹائم پر خصوصیت کے وجود اور قسم کی درستگی کی ضمانت دیتا ہے۔ کارکردگی کے لحاظ سے اہم حصوں (اینیمیشنز، ہزاروں آئٹمز والی فہرستیں) کے لیے، KeyPath واحد صحیح انتخاب ہے۔
اکثر پوچھے گئے سوالات
KeyPath کسی آبجیکٹ کی خصوصیت کا ایک پوائنٹر ہے جسے عام قدر کے طور پر منتقل کیا جا سکتا ہے۔ person.name لکھنے کے بجائے، آپ ایک راستہ \Person.name بناتے ہیں اور اسے کسی بھی Person مثال پر خصوصیت پڑھنے یا لکھنے کے لیے استعمال کرتے ہیں۔
KeyPath — صرف پڑھنا۔ WritableKeyPath — inout سیاق و سباق کے ذریعے ویلیو اقسام (struct) کو پڑھنے اور لکھنے کے لیے۔ ReferenceWritableKeyPath — اضافی شرائط کے بغیر حوالہ اقسام (class) کو پڑھنے اور لکھنے کے لیے۔
KeyPath بڑے پیمانے پر Combine (assign(to:on:)), SwiftUI (Binding, FocusState)، کلیکشن ترتیب (sorted(by:)), Core Data (NSSortDescriptor) اور نیسٹڈ خصوصیات تک محفوظ رسائی کے لیے استعمال ہوتا ہے۔
ہاں، KeyPath مکمل طور پر قسم کے لحاظ سے محفوظ ہے۔ راستے میں غلطی (ٹائپو، غلط قسم) رن ٹائم کے بجائے کمپائل ٹائم پر پکڑی جاتی ہے۔ value(forKey:) سٹرنگ استعمال کرتا ہے اور اگر کلید موجود نہیں ہے تو NSUndefinedKeyException کے ساتھ کریش کر سکتا ہے۔
براہ راست نہیں — Swift سٹرنگ سے متحرک KeyPath تشکیل کی حمایت نہیں کرتا۔ تاہم، آپ جامد طور پر حاصل کردہ KeyPath کو ذخیرہ کرنے اور منتقل کرنے کے لیے AnyKeyPath استعمال کر سکتے ہیں۔ سٹرنگ کے ذریعے متحرک خصوصیت تک رسائی کے لیے، Objective-C رن ٹائم کے ساتھ value(forKey:) استعمال کریں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں