शुद्ध Swift (बिना @objc) में प्रोटोकॉल पर कमजोर संदर्भ कैसे बनाएं? उदाहरणों के साथ पूर्ण गाइड
\n\nकल्पना करें: आप Swift में एक ऐप लिख रहे हैं, Delegate पैटर्न का उपयोग कर रहे हैं, और अचानक — बम! — आपकी वस्तुएं नष्ट नहीं हो रही हैं, मेमोरी बढ़ रही है, और ऐप धीमा होने लगता है। परिचित लगता है? सबसे अधिक संभावना है, आप retain cycle (मजबूत संदर्भों के चक्र) में फंस गए हैं। क्लासिक समस्या जब डेलीगेट मालिक पर मजबूत संदर्भ रखता है, और मालिक डेलीगेट पर। पहला समाधान जो दिमाग में आता है वह है प्रोटोकॉल पर संदर्भ को कमजोर (weak) बनाना। लेकिन यहाँ Swift एक आश्चर्य देता है: यदि प्रोटोकॉल @objc से चिह्नित नहीं है, तो आप आसानी से weak var delegate: MyProtocol घोषित नहीं कर सकते। कंपाइलर एक त्रुटि देगा। क्यों? और सबसे महत्वपूर्ण — इससे कैसे बचें?
इस लेख में, हम जानेंगे कि बिना @objc के शुद्ध Swift में weak protocol reference कैसे बनाया जाए। आप जानेंगे कि यह समस्या क्यों है, इसके क्या समाधान हैं, और मेमोरी लीक के बिना सुंदर, सुरक्षित कोड कैसे लिखें। चलिए शुरू करते हैं!
\n\nweak protocol reference 'बॉक्स से बाहर' क्यों काम नहीं करता?
\n\nआइए याद करें कि Swift में weak कैसे काम करता है। कमजोर संदर्भ (weak) केवल reference types (क्लास) के लिए मौजूद हो सकता है। क्यों? क्योंकि केवल क्लास ऑब्जेक्ट्स में ARC (Automatic Reference Counting) के माध्यम से मेमोरी प्रबंधन होता है। स्ट्रक्चर (struct) और एनुम (enum) — value types हैं, वे कॉपी होते हैं, और उनके लिए 'कमजोर संदर्भ' की अवधारणा का कोई मतलब नहीं है।
जब आप लिखते हैं:
\nweak var delegate: MyProtocol?\nकंपाइलर नहीं जानता कि MyProtocol को क्लास, स्ट्रक्चर या एनुम द्वारा कार्यान्वित किया जाएगा या नहीं। क्या होगा अगर यह एक स्ट्रक्चर है? तब weak लागू नहीं किया जा सकता। इसलिए त्रुटि: «'weak' may only be applied to class and class-bound protocol types».
पहले (Objective-C में) सभी प्रोटोकॉल डिफ़ॉल्ट रूप से केवल क्लास द्वारा कार्यान्वित किए जा सकते थे, इसलिए weak काम करता था। शुद्ध Swift में प्रोटोकॉल सार्वभौमिक हैं — और यह बहुत अच्छा है, लेकिन जटिलताएँ जोड़ता है।
समाधान #1: class-bound प्रोटोकॉल (क्लास तक सीमित प्रोटोकॉल)
\n\nसबसे सरल और सामान्य तरीका — स्पष्ट रूप से निर्दिष्ट करना कि प्रोटोकॉल को केवल क्लास द्वारा कार्यान्वित किया जा सकता है। इसके लिए प्रोटोकॉल घोषणा में कीवर्ड AnyObject (या पुराना class) का उपयोग किया जाता है।
उदाहरण:
\nprotocol MyDelegate: AnyObject {\n func didSomething()\n}\n\nclass ViewController {\n weak var delegate: MyDelegate?\n\n func doSomething() {\n delegate?.didSomething()\n }\n}\n\nclass SomeClass: MyDelegate {\n func didSomething() {\n print("डेलीगेट काम कर गया!")\n }\n}\n\n// उपयोग\nlet vc = ViewController()\nlet some = SomeClass()\nvc.delegate = some\nvc.doSomething() // आउटपुट: "डेलीगेट काम कर गया!"\n\nसब कुछ काम करता है। MyDelegate अब केवल क्लास (class) द्वारा कार्यान्वित किया जा सकता है, और weak कानूनी है। यह डेलीगेट के लिए Apple द्वारा अनुशंसित दृष्टिकोण है।
यह अच्छा क्यों है?
\n- \n
- सरलता और पठनीयता। \n
- ARC का पूर्ण समर्थन। \n
@objcकी कोई आवश्यकता नहीं। \n
नुकसान?
\n- \n
- आप प्रोटोकॉल को स्ट्रक्चर द्वारा कार्यान्वित करने की क्षमता खो देते हैं। लेकिन डेलीगेट के लिए आमतौर पर इसकी आवश्यकता नहीं होती। \n
समाधान #2: जेनेरिक रैपर का उपयोग (असामान्य मामलों के लिए)
\n\nक्या होगा यदि आप अनिवार्य रूप से प्रोटोकॉल को क्लास और स्ट्रक्चर दोनों द्वारा कार्यान्वित करने की अनुमति देना चाहते हैं, लेकिन साथ ही कमजोर संदर्भ चाहते हैं? ऐसा शायद ही कभी होता है, लेकिन संभव है। उदाहरण के लिए, आप एक लाइब्रेरी लिख रहे हैं जहाँ उपयोगकर्ता क्लास और स्ट्रक्चर दोनों पास कर सकता है। तब एक रैपर मदद करता है।
\n\nविचार: एक स्ट्रक्चर बनाएं जो प्रोटोकॉल को कार्यान्वित करने वाली वस्तु पर कमजोर संदर्भ संग्रहीत करता है। क्लास के लिए — we