Delegate একটি ডিজাইন প্যাটার্ন যেখানে একটি অবজেক্ট অন্য অবজেক্টকে কাজ সম্পাদনের দায়িত্ব অর্পণ করে। iOS-এ, প্যাটার্নটি Swift প্রোটোকল এবং @protocol Objective-C-এর মাধ্যমে বাস্তবায়িত হয়। ডেলিগেশন Cocoa Touch-এর মৌলিক প্যাটার্নগুলির মধ্যে একটি, যা UITableViewDelegate, UITextFieldDelegate এবং শত শত অন্যান্য Apple API-তে ব্যবহৃত হয়। Apple Developer Documentation (2025) অনুসারে, প্রায় 70% UIKit সিস্টেম ক্লাস ইনহেরিটেন্স ছাড়াই আচরণ কাস্টমাইজেশনের জন্য ডেলিগেট ব্যবহার করে।
মূল বিষয়
Delegate একটি আচরণগত ডিজাইন প্যাটার্ন যা একটি অবজেক্টকে তার কিছু দায়িত্ব অন্য অবজেক্টের কাছে অর্পণ করতে দেয়। ইনহেরিটেন্সের বিপরীতে, যেখানে চাইল্ড ক্লাস প্যারেন্ট পদ্ধতি ওভাররাইড করে, ডেলিগেট কম্পোজিশন ব্যবহার করে: মালিক অবজেক্ট ডেলিগেটের একটি রেফারেন্স রাখে এবং নির্দিষ্ট পয়েন্টে তার পদ্ধতিগুলি কল করে।
ডেলিগেট একটি প্রোটোকল সংজ্ঞায়িত করে — পদ্ধতির একটি সেট যা ডেলিগেট প্রয়োগ করতে পারে। পদ্ধতিগুলি বাধ্যতামূলক (required) এবং ঐচ্ছিক (optional) এ বিভক্ত। Swift-এ, ঐচ্ছিক প্রোটোকল পদ্ধতিগুলি @objc optional কীওয়ার্ড দিয়ে চিহ্নিত করা হয়।
অবজেক্ট A (মালিক) একটি delegate প্রপার্টি ধারণ করে — অবজেক্ট B (ডেলিগেট)-এর weak রেফারেন্স। যখন একটি ঘটনা ঘটে, A পরীক্ষা করে যে B সংশ্লিষ্ট প্রোটোকল পদ্ধতি প্রয়োগ করে কিনা এবং এটি কল করে। Weak রেফারেন্স বাধ্যতামূলক: এটি ছাড়া, ডেলিগেট মেমরি থেকে মুক্ত হতে পারে না কারণ মালিক তাকে strong রেফারেন্স দিয়ে ধরে রাখে।
protocol LoaderDelegate: AnyObject {
func loaderDidStart(_ loader: DataLoader)
func loader(_ loader: DataLoader, didLoad data: Data)
func loader(_ loader: DataLoader, didFailWith error: Error)
}
class DataLoader {
weak var delegate: LoaderDelegate?
func start() {
delegate?.loaderDidStart(self)
// অ্যাসিনক্রোনাস লোডিং
}
}DataLoader ক্লাস LoaderDelegate প্রোটোকল সংজ্ঞায়িত করে এবং লোডিং লাইফসাইকেলের মূল পয়েন্টে ডেলিগেট পদ্ধতি কল করে। AnyObject গ্যারান্টি দেয় যে প্রোটোকল শুধুমাত্র ক্লাস দ্বারা প্রয়োগ করা যেতে পারে — এটি weak রেফারেন্সের জন্য প্রয়োজনীয়।
Swift-এ ডেলিগেট বাস্তবায়ন তিনটি ধাপ অন্তর্ভুক্ত করে: প্রোটোকল ঘোষণা করা, মালিকে weak delegate প্রপার্টি তৈরি করা, এবং ডেলিগেট ক্লাসে প্রোটোকল প্রয়োগ করা। আসুন ভ্যালিডেশন সহ একটি কাস্টম UITextField-এর উদাহরণ দেখি।
protocol ValidatorDelegate: AnyObject {
func validate(_ input: String) -> Bool
func validatorDidFail(_ input: String)
}
class ValidatedTextField: UITextField {
weak var validator: ValidatorDelegate?
override func textDidChange() {
guard let text = self.text else { return }
if validator?.validate(text) == false {
validator?.validatorDidFail(text)
self.layer.borderColor = UIColor.red.cgColor
}
}
}
class LoginViewController: UIViewController, ValidatorDelegate {
let textField = ValidatedTextField()
override func viewDidLoad() {
super.viewDidLoad()
textField.validator = self
}
func validate(_ input: String) -> Bool {
return input.count >= 6
}
func validatorDidFail(_ input: String) {
print("ভ্যালিডেশন ব্যর্থ হয়েছে: ইনপুট খুব ছোট")
}
}LoginViewController ValidatorDelegate প্রোটোকল প্রয়োগ করে এবং নিজেকে textField-এর ডেলিগেট হিসেবে নিয়োগ করে। প্রতিটি টেক্সট পরিবর্তনে, ValidatedTextField validate(_:) কল করে, এবং যদি ভ্যালিডেশন ব্যর্থ হয় — validatorDidFail(_:) কল করে। কন্ট্রোলার View এবং ভ্যালিডেশন লজিকের মধ্যে মধ্যস্থতাকারী হিসেবে কাজ করে।
ডেলিগেট, বিজ্ঞপ্তি এবং closures-এর মধ্যে নির্বাচন প্রাপকের সংখ্যা এবং কম্পোনেন্ট কাপলিং-এর উপর নির্ভর করে। প্রতিটি প্রক্রিয়া অবজেক্টের মধ্যে যোগাযোগের সমস্যা সমাধান করে, তবে বিভিন্ন ট্রেড-অফ সহ।
| বৈশিষ্ট্য | Delegate | NotificationCenter | Closure |
|---|---|---|---|
| যোগাযোগের ধরন | 1:1 | 1:N | 1:1 |
| কাপলিং | দুর্বল (প্রোটোকলের মাধ্যমে) | অত্যন্ত দুর্বল (স্ট্রিং কী) | মাঝারি (কনটেক্সট ক্যাপচার) |
| টাইপ নিরাপত্তা | সম্পূর্ণ | কোনোটিই নয় (Any?) | সম্পূর্ণ |
| Retain cycle ঝুঁকি | না (weak) | না | হ্যাঁ (self ক্যাপচার) |
| কখন ব্যবহার করবেন | একাধিক পদ্ধতি সহ জটিল কলব্যাক | ঘটনা যা অনেককে আগ্রহী করে | 1-2 কলব্যাক সহ সহজ closures |
Delegate তখন সর্বোত্তম যখন আপনাকে সম্পর্কিত ঘটনার একটি সিরিজ একক প্রাপকের কাছে পাঠাতে হবে। NotificationCenter ব্রডকাস্ট বিজ্ঞপ্তির জন্য ভাল। Closure সহজ অ্যাসিনক্রোনাস অপারেশনের জন্য, যেমন URLSession-এ কমপ্লিশন হ্যান্ডলার।
Objective-C ডেলিগেট ঘোষণার জন্য @protocol এবং @optional ব্যবহার করে। Swift-এর বিপরীতে, সমস্ত প্রোটোকল পদ্ধতি ডিফল্টরূপে ঐচ্ছিক। মূল পার্থক্য হল ডেলিগেটে বার্তা পাঠানোর আগে respondsToSelector: কল, কারণ পদ্ধতিটি প্রয়োগ নাও হতে পারে।
@protocol ImageCacheDelegate
@optional
- (void)cacheDidStartDownload: (ImageCache *)cache;
- (void)cache: (ImageCache *)cache didCacheImage: (UIImage *)image;
@required
- (void)cache: (ImageCache *)cache didFailWithError: (NSError *)error;
@end
@interface ImageCache : NSObject
@property (nonatomic, weak) id<ImageCacheDelegate> delegate;
- (void)downloadImageAtURL: (NSURL *)url;
@end
@implementation ImageCache
- (void)downloadImageAtURL: (NSURL *)url {
if ([self.delegate respondsToSelector:@selector(cacheDidStartDownload:)]) {
[self.delegate cacheDidStartDownload:self];
}
// অ্যাসিনক্রোনাস ইমেজ লোডিং
}
@endObjective-C-তে মূল পার্থক্য: একটি ঐচ্ছিক পদ্ধতি কল করার আগে respondsToSelector: পরীক্ষা প্রয়োজন। Swift-এ, ঐচ্ছিক প্রোটোকল পদ্ধতি এই পরীক্ষাটি বাতিল করে — optional chaining (?.) স্বয়ংক্রিয়ভাবে প্রয়োগের অনুপস্থিতি পরিচালনা করে।
ডেলিগেট ব্যবহারের ভুল মেমরি লিক, অ্যাপ ক্র্যাশ এবং অস্পষ্ট বাগ সৃষ্টি করে। চলুন পাঁচটি সবচেয়ে সাধারণ সমস্যা দেখি।
Retain cycle সবচেয়ে সাধারণ ভুল। যদি delegate প্রপার্টি strong হিসেবে ঘোষিত হয়, এবং ডেলিগেট ফলেস্বরূপ মালিক অবজেক্টের মালিক হয়, তাহলে একটি ধারণ চক্র তৈরি হয়। উভয় অবজেক্ট কখনো মেমরি থেকে মুক্ত হবে না। সমাধান: সর্বদা Swift-এ weak var বা Objective-C-এ @property (weak) হিসেবে ডেলিগেট ঘোষণা করুন।
যদি মালিক অবজেক্ট ডেলিগেটের চেয়ে বেশি বেঁচে থাকে এবং রেফারেন্স থেকে যায়, তাহলে ডেলিগেট পদ্ধতি কল করলে EXC_BAD_ACCESS হবে। Weak রেফারেন্স স্বয়ংক্রিয়ভাবে এই সমস্যা সমাধান করে: ডেলিগেট মুক্ত হওয়ার পর, প্রপার্টি nil হয়ে যায়। তবে, মাল্টিথ্রেডেড পরিস্থিতিতে, মূল থ্রেডে অতিরিক্তভাবে ডেলিগেট পরীক্ষা করা উচিত।
20+ পদ্ধতি সহ একটি প্রোটোকল ইন্টারফেস সেগ্রিগেশন প্রিন্সিপল (ISP) লঙ্ঘন করে। UITableViewDelegate-এ প্রায় 30টি ঐচ্ছিক পদ্ধতি রয়েছে — এটি একটি ঐতিহাসিক ব্যতিক্রম। আপনার নিজের প্রোটোকলে, দায়িত্ব কয়েকটি ছোট প্রোটোকলে ভাগ করা ভাল, প্রতিটির নিজস্ব ভূমিকা থাকবে।
Apple-এর সিস্টেম API সক্রিয়ভাবে Delegate প্যাটার্ন ব্যবহার করে। আসুন UIKit-এর তিনটি মূল উদাহরণ দেখি যা প্রতিটি iOS অ্যাপ্লিকেশনে দেখা যায়।
| API | প্রোটোকল | মূল পদ্ধতি |
|---|---|---|
| UITableView | UITableViewDelegate | didSelectRowAt, heightForRowAt, willDisplay |
| UITextField | UITextFieldDelegate | shouldChangeCharactersIn, didBeginEditing, shouldReturn |
| URLSession | URLSessionDelegate | didReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError |
এই প্রোটোকলগুলির প্রতিটি আচরণের বিভিন্ন দিক প্রয়োগ করে: UITableViewDelegate চেহারা এবং স্পর্শ প্রতিক্রিয়া পরিচালনা করে, UITextFieldDelegate টেক্সট ইনপুট নিয়ন্ত্রণ করে, URLSessionDelegate নেটওয়ার্ক ইভেন্টগুলি পরিচালনা করে। এটি প্যাটার্নের নমনীয়তা প্রদর্শন করে: ডেলিগেট দায়িত্বের যেকোনো ক্ষেত্রের সাথে খাপ খাইয়ে নেওয়া যেতে পারে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Delegate আচরণ এবং চেহারা পরিচালনা করে (সেল উচ্চতা, স্পর্শ প্রতিক্রিয়া)। DataSource ডেটা সরবরাহ করে (সারির সংখ্যা, সেল বিষয়বস্তু)। UITableViewDelegate এবং UITableViewDataSource-এ — এগুলি দুটি পৃথক প্রোটোকল যা উপস্থাপনা এবং ডেটার জন্য দায়িত্ব ভাগ করে।
Weak রেফারেন্স retain cycle প্রতিরোধ করে। মালিক (যেমন, UITableView) শুধুমাত্র weak হিসেবে ডেলিগেটের রেফারেন্স রাখে। যদি ডেলিগেট (UIViewController) টেবিলের মালিক হয়, তাহলে ডেলিগেটের strong রেফারেন্স একটি চক্র তৈরি করবে: ViewController → UITableView → Delegate (ViewController)। Weak এই চক্র ভেঙে দেয়।
SwiftUI-তে, Delegate প্যাটার্ন কম ব্যবহৃত হয় — এটি @Binding, @State এবং closures দ্বারা প্রতিস্থাপিত হয়। তবে, UIViewRepresentable-এর মাধ্যমে UIKit ইন্টিগ্রেশনের জন্য ডেলিগেট এখনও ব্যবহৃত হয়। উদাহরণস্বরূপ, MKMapViewDelegate এবং WKUIDelegate UIKit উপাদানগুলিকে SwiftUI-তে মোড়ানোর সময় প্রাসঙ্গিক থাকে।
@objc optional Swift প্রোটোকলে ঐচ্ছিক পদ্ধতি ঘোষণা করার অনুমতি দেয়। এটি Objective-C রানটাইমের সাথে সামঞ্জস্যতার প্রক্রিয়া। @objc ছাড়া, সমস্ত Swift প্রোটোকল পদ্ধতি ডিফল্টরূপে বাধ্যতামূলক। Optional UIKit প্রোটোকলে ব্যবহৃত হয় যেখানে ডেলিগেট শুধুমাত্র তার প্রয়োজনীয় পদ্ধতিগুলি প্রয়োগ করতে পারে।
একটি অবজেক্টের প্রতিটি delegate প্রপার্টির জন্য শুধুমাত্র একটি ডেলিগেট থাকতে পারে। যদি আপনাকে একাধিক অবজেক্টকে জানাতে হয়, তাহলে multicast delegate, ডেলিগেটের একটি অ্যারে, বা NotificationCenter ব্যবহার করুন। Delegate প্যাটার্ন মূলত 1:1 সম্পর্ক হিসাবে ডিজাইন করা হয়েছে।
সংক্ষিপ্তসার
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন