Delegate হল একটি ডিজাইন প্যাটার্ন যেখানে একটি অবজেক্ট পূর্বনির্ধারিত পদ্ধতি সহ একটি প্রোটোকলের মাধ্যমে অন্য একটি অবজেক্টকে কাজ সম্পাদনের দায়িত্ব অর্পণ করে। iOS ডেভেলপমেন্টে, Delegate হল Cocoa Touch-এর মৌলিক প্যাটার্নগুলির মধ্যে একটি, যা প্রেরক এবং গ্রহীতার মধ্যে সরাসরি সংযোগ ছাড়াই অ্যাসিঙ্ক্রোনাস বিজ্ঞপ্তির জন্য ব্যবহৃত হয়। Apple Documentation (2025) অনুসারে, Foundation এবং UIKit-এ টেবিল ইভেন্ট, নেটওয়ার্ক অনুরোধ এবং অবস্থান ব্যবস্থাপনা পরিচালনার জন্য প্রতিনিধিত্ব ব্যবহার করা হয়। প্যাটার্নটি উপাদানগুলির শিথিল সংযোগ এবং কোড পুনঃব্যবহার নিশ্চিত করে।
মূল পয়েন্ট
Delegate (প্রতিনিধি) হল একটি অবজেক্ট যা একটি নির্দিষ্ট প্রোটোকল বাস্তবায়ন করে এবং অন্য একটি অবজেক্টের ইভেন্ট সম্পর্কে বিজ্ঞপ্তি গ্রহণ করে। প্রতিনিধিত্ব প্যাটার্নটি উত্তরাধিকারের একটি বিকল্প: পদ্ধতি ওভাররাইড করার জন্য একটি উপশ্রেণী তৈরি করার পরিবর্তে, একটি অবজেক্ট ইভেন্ট হ্যান্ডলিং একটি বাহ্যিক অবজেক্টকে অর্পণ করে। iOS-এ, প্রতিনিধিত্ব প্রয়োজনীয় এবং ঐচ্ছিক পদ্ধতি সহ Swift প্রোটোকলের মাধ্যমে বাস্তবায়িত হয়। delegate প্রপার্টি সর্বদা weak var হিসাবে ঘোষণা করা হয় অবজেক্টগুলির মধ্যে চক্রীয় রেফারেন্স এড়াতে।
একটি delegate প্রোটোকল অবজেক্টগুলির মধ্যে মিথস্ক্রিয়া চুক্তি সংজ্ঞায়িত করে। প্রয়োজনীয় পদ্ধতিগুলি প্রতিনিধি দ্বারা বাস্তবায়িত হতে হবে, অন্যথায় কোড কম্পাইল হবে না। ঐচ্ছিক পদ্ধতিগুলি @objc optional অ্যাট্রিবিউট দিয়ে চিহ্নিত করা হয় এবং প্রতিনিধিকে শুধুমাত্র প্রাসঙ্গিক ইভেন্টগুলিতে সাড়া দিতে দেয়। পদ্ধতির নামগুলি একটি নিয়ম অনুসরণ করে: প্রথম প্যারামিটারটি প্রেরক অবজেক্ট, দ্বিতীয়টি ইভেন্ট ডেটা। উদাহরণস্বরূপ, tableView(_:didSelectRowAt:) নির্দেশ করে যে প্রেরক হল UITableView এবং ডেটা হল নির্বাচিত সারির সূচক।
// Delegate প্রোটোকল
protocol DownloadManagerDelegate: AnyObject {
func downloadManager(_ manager: DownloadManager,
didFinishWith data: Data)
func downloadManager(_ manager: DownloadManager,
didFailWith error: Error)
@objc optional func downloadManager(_ manager: DownloadManager,
didUpdateProgress progress: Float)
}
// Delegate ব্যবহার করে ক্লাস
class DownloadManager {
weak var delegate: DownloadManagerDelegate?
func startDownload(from url: URL) {
URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let self else { return }
if let error = error {
self.delegate?.downloadManager(self, didFailWith: error)
} else if let data = data {
self.delegate?.downloadManager(self, didFinishWith: data)
}
}.resume()
}
}
delegate প্রপার্টিটি retain cycle প্রতিরোধ করতে weak var হিসাবে ঘোষণা করা আবশ্যক। যদি রেফারেন্সটি শক্তিশালী হত, তাহলে প্রতিনিধি এবং প্রতিনিধিত্বকারী অবজেক্ট একে অপরকে ধরে রাখত, এবং ARC তাদের মেমরি মুক্ত করতে সক্ষম হত না। delegate প্রোটোকলগুলি AnyObject (শুধুমাত্র ক্লাস) থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়, যা weak ব্যবহারের অনুমতি দেয়। স্ট্রাকচার এবং এনাম মান শব্দার্থবিদ্যার কারণে প্রতিনিধি হতে পারে না। মান প্রকারের জন্য বিকল্প হল callback closures।
class ViewController: DownloadManagerDelegate {
let manager = DownloadManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self // weak — কোনো retain cycle নেই
manager.startDownload(from: url)
}
func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
processData(data)
}
func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
showError(error)
}
}
Delegate প্যাটার্ন এক-থেকে-এক ভিত্তিতে কাজ করে: একটি প্রেরক অবজেক্টের একটি নির্দিষ্ট সময়ে শুধুমাত্র একটি delegate থাকতে পারে। যখন একটি ইভেন্ট ঘটে, প্রেরক পরীক্ষা করে যে delegate সেট করা আছে কিনা এবং সংশ্লিষ্ট প্রোটোকল পদ্ধতি কল করে। সরাসরি কলের উপর সুবিধা হল যে প্রেরক delegate-এর ধরন জানে না, শুধু জানে যে এটি প্রোটোকল মেনে চলে। এটি SOLID-এর নির্ভরতা বিপরীত নীতি (DIP) মেনে চলে।
প্রতিনিধি অ্যাসাইনমেন্টের মাধ্যমে নিযুক্ত করা হয়: someObject.delegate = self। যখন প্রতিনিধি ডিলোকেট হয়, প্রপার্টিটি weak শব্দার্থবিদ্যার কারণে স্বয়ংক্রিয়ভাবে nil হয়ে যায়। একটি প্রতিনিধি পদ্ধতি কল করার আগে, ঐচ্ছিক চেইনিংয়ের মাধ্যমে প্রতিনিধি পরীক্ষা করা হয়: delegate?.method()। যদি delegate nil হয়, কলটি ক্র্যাশ ছাড়াই উপেক্ষা করা হয়। ঐচ্ছিক প্রোটোকল পদ্ধতিগুলির জন্য, একটি অতিরিক্ত পরীক্ষা ব্যবহার করা হয়: delegate?.responds(to: #selector(...)), যদিও Swift-এ এই পরীক্ষাটি সাধারণত ঐচ্ছিক পদ্ধতি ঘোষণার মাধ্যমে অন্তর্নিহিত হয়।
একটি মাল্টিথ্রেডেড পরিবেশে, অ্যাসিঙ্ক্রোনাস ফলাফল ফেরতের জন্য delegate ব্যবহার করা হয়। URLSession ডেটা প্রাপ্ত হলে, টাইমআউট বা প্রমাণীকরণ ত্রুটিতে কল করা পদ্ধতি সহ URLSessionDelegate প্রদান করে। প্রতিনিধি পদ্ধতিগুলি URLSession-এর পটভূমি সারিতে কার্যকর হয়, তাই UI আপডেটের জন্য মূল সারিতে প্রেরণ প্রয়োজন। অ্যাসিঙ্ক্রোনাস delegate কলিং থ্রেডকে ব্লক করে না, অন্যান্য কাজ চালিয়ে যাওয়ার অনুমতি দেয়।
class NetworkService: NSObject, URLSessionDataDelegate {
private lazy var session = URLSession(
configuration: .default,
delegate: self,
delegateQueue: OperationQueue()
)
private var receivedData = Data()
func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive data: Data) {
receivedData.append(data)
let progress = Float(receivedData.count) / Float(expectedSize)
DispatchQueue.main.async {
self.progressHandler?(progress)
}
}
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
if let error = error {
delegate?.networkService(self, didFailWith: error)
} else {
delegate?.networkService(self, didReceive: receivedData)
}
}
}
Delegate এবং Callback একই সমস্যা — অ্যাসিঙ্ক্রোনাস বিজ্ঞপ্তি — কিন্তু ভিন্ন উপায়ে সমাধান করে। Delegate নামযুক্ত পদ্ধতি সহ একটি প্রোটোকল ব্যবহার করে, callback প্রসঙ্গ ক্যাপচার সহ একটি ক্লোজার ব্যবহার করে। পছন্দটি ইভেন্টের সংখ্যা, স্বাক্ষর জটিলতা এবং স্থাপত্য পছন্দের উপর নির্ভর করে। Apple একাধিক ইভেন্ট সহ API-এর জন্য delegate (UITableView — 20+ পদ্ধতি) এবং এককালীন সমাপ্তির জন্য callback সুপারিশ করে।
একক উৎস থেকে একাধিক ভিন্ন ইভেন্ট পরিচালনা করার সময় Delegate পছন্দনীয়। উদাহরণস্বরূপ, CLLocationManager তার প্রতিনিধিকে অবস্থান পরিবর্তন, অনুমতি ত্রুটি, জিও-ফেন্স এন্ট্রি/এক্সিট এবং পরিষেবা স্থিতি পরিবর্তন সম্পর্কে জানায়। প্রতিটি ইভেন্ট একটি স্পষ্ট নাম এবং টাইপ করা প্যারামিটার সহ একটি পৃথক প্রোটোকল পদ্ধতি। Delegate আচরণ কনফিগারেশনের জন্যও সুবিধাজনক (should, will, did পদ্ধতি)।
একক ফলাফল সহ এককালীন অনুরোধের জন্য Callback সহজ। URLSession.dataTask-এ Completion handler কল সাইটে কমপক্ষে তিনটি প্রোটোকল পদ্ধতির তুলনায় একটি লাইন নেয়। Callback ফাংশনাল চেইন (map, flatMap, async/await) এর জন্যও বেশি স্বাভাবিক। তবে, 2-3 স্তরের বেশি নেস্টিং সহ, callback Callback Hell-এ পরিণত হয়, যেখানে delegate সর্বদা সমতল থাকে।
iOS SDK-এ বিভিন্ন উপ-সিস্টেমের জন্য ডজন ডজন নির্মিত delegate প্রোটোকল রয়েছে। প্রতিটি একটি নির্দিষ্ট মিথস্ক্রিয়া পরিস্থিতির জন্য ডিজাইন করা হয়েছে। Apple Documentation (2025) অনুসারে, সবচেয়ে বেশি ব্যবহৃত প্রতিনিধিরা হল UITableViewDelegate, UITextFieldDelegate, CLLocationManagerDelegate, URLSessionDelegate এবং UNUserNotificationCenterDelegate। এই প্রোটোকলগুলিতে প্রয়োজনীয়তার বিভিন্ন স্তর সহ 3 থেকে 30টি পদ্ধতি রয়েছে।
UITableViewDelegate টেবিল কোষের চেহারা এবং আচরণ পরিচালনা করে। এতে সারি নির্বাচন পরিচালনা, কোষের উচ্চতা কনফিগার, কাস্টম হেডার/ফুটার ভিউ এবং সোয়াইপ অ্যাকশনের জন্য পদ্ধতি রয়েছে। সমস্ত প্রোটোকল পদ্ধতি ঐচ্ছিক, যা শুধুমাত্র প্রয়োজনীয় কার্যকারিতা বাস্তবায়নের অনুমতি দেয়। প্রতিনিধি ছাড়া, টেবিল ডিফল্ট সেটিংসে কাজ করে। ঐতিহাসিকভাবে, delegate UITableViewDataSource-এর সাথে যুক্ত ছিল।
URLSessionDelegate HTTP অনুরোধের উপর বিস্তারিত নিয়ন্ত্রণ প্রদান করে। সার্ভার প্রতিক্রিয়া প্রাপ্ত হলে, ডেটা আসলে বা ডাউনলোড সম্পূর্ণ হলে প্রতিনিধি পদ্ধতিগুলি কল করা হয়। নির্দিষ্ট কাজের প্রকারের জন্য মৌলিক কার্যকারিতা প্রসারিত করে এমন বিশেষায়িত উপ-প্রোটোকল URLSessionTaskDelegate এবং URLSessionDataDelegate। পটভূমি ডাউনলোড, SSL সার্টিফিকেট এবং কাস্টম রিডাইরেক্ট হ্যান্ডলিং সমর্থনের জন্য প্রতিনিধি প্রয়োজন।
| Delegate | পদ্ধতি | উদ্দেশ্য |
|---|---|---|
| UITableViewDelegate | 25 | টেবিলের চেহারা এবং মিথস্ক্রিয়া |
| UITextFieldDelegate | 8 | টেক্সট ইনপুট এবং কীবোর্ড হ্যান্ডলিং |
| CLLocationManagerDelegate | 12 | অবস্থান আপডেট এবং জিও-ফেন্স |
| URLSessionDelegate | 6 | HTTP সেশন এবং সার্টিফিকেট ব্যবস্থাপনা |
| UNUserNotificationCenterDelegate | 4 | অগ্রভাগ পুশ বিজ্ঞপ্তি হ্যান্ডলিং |
মেমরি ব্যবস্থাপনা iOS-এ delegate-এর সাথে কাজ করার একটি গুরুত্বপূর্ণ দিক। ARC (স্বয়ংক্রিয় রেফারেন্স গণনা) স্বয়ংক্রিয়ভাবে মেমরি পরিচালনা করে, কিন্তু শুধুমাত্র weak/unowned রেফারেন্সের সঠিক ব্যবহারের সাথে। নিয়ম লঙ্ঘন করলে মেমরি লিক বা অকাল ডিলোকেশন হয়। strong হিসাবে ঘোষিত একটি প্রতিনিধি retain cycle তৈরি করে যদি প্রতিনিধি মালিক প্রতিনিধিত্বকারী অবজেক্টেরও একটি রেফারেন্স রাখে।
Retain cycle ঘটে যখন অবজেক্ট A (মালিক) নিজেকে অবজেক্ট B-এর প্রতিনিধি হিসাবে সেট করে, এবং B প্রতিনিধির জন্য একটি শক্তিশালী রেফারেন্স রাখে। উদাহরণ: ViewController URLSession তৈরি করে, নিজেকে সেশনের প্রতিনিধি হিসাবে সেট করে, কিন্তু URLSession ডিফল্টরূপে প্রতিনিধির জন্য একটি শক্তিশালী রেফারেন্স রাখে যদি delegateQueue নির্দিষ্ট না করা হয়। সমাধান হল সর্বদা প্রতিনিধি রেফারেন্স টাইপ (weak বা strong) এর জন্য API ডকুমেন্টেশন পরীক্ষা করা এবং deinit-এ প্রতিনিধিকে স্পষ্টভাবে nil করা।
class SafeViewController: UIViewController {
private var session: URLSession?
private var service: NetworkService?
override func viewDidLoad() {
super.viewDidLoad()
service = NetworkService()
service?.delegate = self
}
deinit {
// deinit-এ delegate কে nil এ সেট করুন — best practice
service?.delegate = nil
session?.invalidateAndCancel()
}
}
// NSObject-এর মাধ্যমে weak delegate সহ URLSession
class WeakDelegateSession: NSObject {
private weak var delegate: URLSessionDelegate?
func createSession() -> URLSession {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return URLSession(
configuration: .default,
delegate: self,
delegateQueue: queue
)
}
}
একটি প্রতিনিধি পদ্ধতি কল করার আগে, আপনাকে অবশ্যই যাচাই করতে হবে যে প্রতিনিধি বিদ্যমান (nil নয়) এবং কল করা পদ্ধতি বাস্তবায়ন করে। প্রয়োজনীয় প্রোটোকল পদ্ধতির জন্য, কোনও পরীক্ষার প্রয়োজন নেই — কম্পাইলার বাস্তবায়নের নিশ্চয়তা দেয়। ঐচ্ছিক পদ্ধতির জন্য, respond(to:) বা ঐচ্ছিক চেইনিং ব্যবহার করুন। যদি প্রতিনিধি ডিলোকেট হয়, weak রেফারেন্স স্বয়ংক্রিয়ভাবে nil হয়ে যায়, এবং প্রতিনিধি কল উপেক্ষা করা হয়। এটি নিরাপদ আচরণ যার অতিরিক্ত হ্যান্ডলিং প্রয়োজন নেই।
ডেভেলপাররা প্রায়শই Delegate প্যাটার্ন নিয়ে কাজ করার সময় ভুল করে, বিশেষ করে iOS শেখার প্রাথমিক পর্যায়ে। সবচেয়ে সাধারণগুলির মধ্যে রয়েছে: strong delegate-এর কারণে retain cycle, delegate?.method() কল করতে ভুলে যাওয়া, ভুল প্রোটোকল পদ্ধতি স্বাক্ষর, অপারেশন শুরু করার পরে প্রতিনিধি সেট করা এবং মাল্টিথ্রেডিং সংঘর্ষ। আসুন প্রতিটি ভুল এবং এটি প্রতিরোধের উপায় দেখি।
সবচেয়ে গুরুত্বপূর্ণ ভুল হল delegate প্রপার্টিকে weak var-এর পরিবর্তে strong var হিসাবে ঘোষণা করা। এটি একটি retain cycle তৈরি করে যেখানে প্রতিনিধি বা প্রতিনিধিত্বকারী অবজেক্ট কোনটিই মুক্ত করা যায় না। ফলাফল: মেমরি লিক, অ্যাপ ধীরগতি এবং লুকানো বাগ। সমাধান: সর্বদা delegate-এর জন্য weak var ব্যবহার করুন এবং প্রোটোকলকে AnyObject থেকে উত্তরাধিকার সূত্রে প্রাপ্ত করান যাতে মান প্রকারগুলিকে প্রতিনিধি হিসাবে ব্যবহার করা থেকে বিরত রাখা যায়।
যদি একটি অ্যাসিঙ্ক্রোনাস পদ্ধতি কল করার পরে প্রতিনিধি সেট করা হয়, প্রথম ইভেন্টগুলি হারিয়ে যেতে পারে। উদাহরণ: manager.delegate = self অ্যাসাইন করার আগে startDownload() কল করলে সম্পূর্ণতা কলব্যack মিস হয় যদি ডাউনলোড সিঙ্ক্রোনাসভাবে বা খুব দ্রুত কার্যকর হয়। সমাধান: অ্যাসিঙ্ক্রোনাস পদ্ধতি কল করার আগে প্রতিনিধি সেট করুন এবং প্রোটোকল মন্তব্যে initialization ক্রম ডকুমেন্ট করুন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Weak প্রতিনিধি এবং প্রতিনিধিত্বকারী অবজেক্টের মধ্যে retain cycle প্রতিরোধ করে। যদি রেফারেন্সটি শক্তিশালী হত, অবজেক্টগুলি একে অপরকে ধরে রাখত, এবং ARC তাদের মুক্ত করতে সক্ষম হত না। একটি weak রেফারেন্স স্বয়ংক্রিয়ভাবে nil হয়ে যায় যখন প্রতিনিধি ডিলোকেট হয়। এটি Objective-C-এর আবির্ভাবের পর থেকে একটি মানক Cocoa Touch অনুশীলন এবং পিছনের সামঞ্জস্যের জন্য Swift-এ সংরক্ষিত।
Delegate ইভেন্টগুলি পরিচালনা করে এবং আচরণ পরিচালনা করে (কোষের উচ্চতা, ট্যাপে প্রতিক্রিয়া)। DataSource প্রদর্শনের জন্য ডেটা সরবরাহ করে (সারির সংখ্যা, কোষ)। প্রতিনিধি “কিভাবে?” প্রশ্নের উত্তর দেয়, dataSource “কী?” প্রশ্নের উত্তর দেয়। iOS-এ, উভয়ই প্রোটোকলের মাধ্যমে বাস্তবায়িত হয়, প্রায়শই একই নিয়ন্ত্রকে, কিন্তু ধারণাগতভাবে পৃথক।
না, যদি প্রোটোকল AnyObject (ক্লাস প্রোটোকল) থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়। weak রেফারেন্স শুধুমাত্র রেফারেন্স প্রকারের (ক্লাস) জন্য উপলব্ধ। মান প্রকারের (struct, enum) জন্য, callback closures বা একটি পৃথক র্যাপার ক্লাস ব্যবহার করুন। আপনি যদি প্রোটোকল নিয়ন্ত্রণ করেন, আপনি AnyObject থেকে উত্তরাধিকার এড়াতে পারেন, কিন্তু তখন weak নিষিদ্ধ — সচেতনভাবে weak প্রতিনিধি এবং struct প্রতিনিধির মধ্যে বেছে নিন।
responds(to:) একটি NSObjectProtocol পদ্ধতি যা পরীক্ষা করে যে একটি অবজেক্ট নির্দিষ্ট সিলেক্টর বাস্তবায়ন করে কিনা। এটি কল করার আগে ঐচ্ছিক @objc প্রোটোকল পদ্ধতি পরীক্ষা করতে ব্যবহৃত হয়। এই পরীক্ষা ছাড়া, একটি অবাস্তবায়িত ঐচ্ছিক পদ্ধতি কল করলে NSInvalidArgumentException হবে। Swift-এ, @objc optional সহ প্রোটোকলের জন্য, পরীক্ষাটি ঐচ্ছিক বাইন্ডিংয়ের মাধ্যমে অন্তর্নিহিত হতে পারে।
না, delegate একটি প্রতিনিধিত্ব প্যাটার্ন, সিঙ্গলটন নয়। সিঙ্গলটনের বিপরীতে, একজন প্রতিনিধি রানটাইমে প্রতিস্থাপন করা যেতে পারে এবং প্রতিটি প্রতিনিধিত্বকারী অবজেক্টের জন্য একটি একক উদাহরণে বিদ্যমান থাকে। একটি অবজেক্ট একাধিক প্রেরকের জন্য প্রতিনিধি হতে পারে। সিঙ্গলটন হল একটি সৃজনশীল প্যাটার্ন যা একটি একক ক্লাস উদাহরণের নিশ্চয়তা দেয়, যার প্রতিনিধিত্বের সাথে কোনও সম্পর্ক নেই।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন