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 (ڈیلیگیٹ) کا کمزور حوالہ۔ جب کوئی واقعہ پیش آتا ہے، A چیک کرتا ہے کہ آیا B متعلقہ پروٹوکول طریقہ کو نافذ کرتا ہے اور اسے کال کرتا ہے۔ کمزور حوالہ لازمی ہے: اس کے بغیر، ڈیلیگیٹ میموری سے آزاد نہیں ہو سکتا کیونکہ مالک اسے مضبوط حوالے سے رکھتا ہے۔
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 اس بات کی ضمانت دیتا ہے کہ پروٹوکول صرف کلاسز کے ذریعے نافذ کیا جا سکتا ہے — یہ کمزور حوالے کے لیے ضروری ہے۔
Swift میں ڈیلیگیٹ کا نفاذ تین مراحل پر مشتمل ہے: پروٹوکول کا اعلان، مالک میں کمزور 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 ہوگا۔ کمزور حوالہ اس مسئلے کو خود بخود حل کرتا ہے: ڈیلیگیٹ کے آزاد ہونے کے بعد، پراپرٹی 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 میں — یہ دو علیحدہ پروٹوکول ہیں جو پریزنٹیشن اور ڈیٹا کی ذمہ داری کو تقسیم کرتے ہیں۔
کمزور حوالہ retain cycle کو روکتا ہے۔ مالک (مثال کے طور پر، UITableView) ڈیلیگیٹ کا حوالہ صرف weak کے طور پر رکھتا ہے۔ اگر ڈیلیگیٹ (UIViewController) ٹیبل کا مالک ہے، تو ڈیلیگیٹ کا مضبوط حوالہ ایک چکر بنائے گا: 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 پراپرٹی کے لیے صرف ایک ڈیلیگیٹ ہو سکتا ہے۔ اگر آپ کو متعدد آبجیکٹس کو مطلع کرنے کی ضرورت ہے، تو ملٹی کاسٹ ڈیلیگیٹ، ڈیلیگیٹ کی ایک صف، یا NotificationCenter استعمال کریں۔ Delegate پیٹرن اصل میں 1:1 تعلق کے طور پر ڈیزائن کیا گیا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں