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 runtime প্রক্রিয়ার মাধ্যমে সমাধান করা হয়, যার মধ্যে স্ট্রিং পার্সিং, runtime লুকআপ এবং টাইপ কাস্টিং অন্তর্ভুক্ত। KeyPath নেটিভ Swift কাঠামোর উপর ভিত্তি করে একটি স্থির প্রক্রিয়া।
বেনচমার্ক অনুসারে, প্রপার্টি অ্যাক্সেসের জন্য KeyPath গড়ে value(forKey:)-এর চেয়ে 10-20 গুণ দ্রুততর। পার্থক্যটি runtime লুকআপ এবং ডায়নামিক ডিসপ্যাচের অনুপস্থিতির কারণে। 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 সম্পূর্ণ টাইপ-নিরাপদ। পথে ত্রুটি (টাইপো, ভুল টাইপ) runtime-এর পরিবর্তে কম্পাইল টাইমে ধরা পড়ে। value(forKey:) স্ট্রিং ব্যবহার করে এবং কী বিদ্যমান না থাকলে NSUndefinedKeyException-এর সাথে ক্র্যাশ হতে পারে।
সরাসরি না — Swift স্ট্রিং থেকে ডায়নামিক KeyPath তৈরি সমর্থন করে না। তবে, আপনি স্ট্যাটিকভাবে প্রাপ্ত KeyPath সংরক্ষণ এবং পাস করতে AnyKeyPath ব্যবহার করতে পারেন। স্ট্রিং দ্বারা ডায়নামিক প্রপার্টি অ্যাক্সেসের জন্য, Objective-C runtime-এর সাথে value(forKey:) ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন