Swift इंटरव्यू कैसे पास करें: एडवांस्ड लेवल
\n\nSenior iOS डेवलपर या Team Lead की पोजीशन के लिए इंटरव्यू सिर्फ सिंटैक्स जानने की परीक्षा नहीं है। इंटरव्यूअर यह देखना चाहते हैं कि आप Swift की आंतरिक संरचना को कितनी गहराई से समझते हैं, आर्किटेक्चर डिज़ाइन कर सकते हैं और आम समस्याओं से बच सकते हैं। इस लेख में हम एडवांस्ड लेवल के 4 ब्लॉक सवालों को कवर करेंगे जो अक्सर इंटरव्यू में पूछे जाते हैं। प्रत्येक ब्लॉक में कोड उदाहरण और स्पष्टीकरण दिए गए हैं ताकि आप आत्मविश्वास से जवाब दे सकें।
\n\n1. Automatic Reference Counting (ARC) और मेमोरी मैनेजमेंट
\n\nARC एक प्रमुख विषय है। इंटरव्यूअर स्ट्रॉन्ग रेफरेंस साइकल (strong reference cycles) और उन्हें तोड़ने के तरीकों के बारे में पूछ सकता है।
सवाल: कैप्चर लिस्ट क्या है और यह closures में retain cycle से बचने में कैसे मदद करती है?
\n\nSwift में closures रेफरेंस टाइप होते हैं। अगर कोई closure self को कैप्चर करता है (जैसे, किसी क्लास की प्रॉपर्टी), और वही ऑब्जेक्ट इस closure को स्टोर करता है, तो एक साइकल बन जाता है। इसका समाधान capture list का उपयोग [weak self] या [unowned self] मॉडिफायर के साथ करना है।
class NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n // खतरनाक: स्ट्रॉन्ग रेफरेंस कैप्चर\n onComplete = {\n self.processData() // retain cycle!\n }\n\n // सही तरीका: वीक कैप्चर\n onComplete = { [weak self] in\n guard let self = self else { return }\n self.processData()\n }\n }\n\n func processData() { print("Processing...") }\n deinit { print("NetworkManager deallocated") }\n}\n\nमहत्वपूर्ण: unowned self का उपयोग केवल तभी करें जब आप सुनिश्चित हों कि closure को कॉल करते समय ऑब्जेक्ट जीवित रहेगा। अन्यथा weak self का उपयोग करें।
2. जेनेरिक्स (Generics) और associatedtype वाले प्रोटोकॉल
\n\nएडवांस्ड लेवल में जेनेरिक कोड लिखने और associatedtype वाले प्रोटोकॉल की सीमाओं को समझना शामिल है।
\n\nसवाल: associatedtype वाले प्रोटोकॉल और generics वाले प्रोटोकॉल में क्या अंतर है? Opaque Types (some) का उपयोग कैसे करें?
\n\nassociatedtype वाले प्रोटोकॉल को स्वतंत्र टाइप के रूप में उपयोग नहीं किया जा सकता। विशिष्ट टाइप को छिपाने के लिए Swift 5.1 में पेश किए गए some कीवर्ड (opaque return type) का उपयोग किया जाता है।
// एसोसिएटेड टाइप वाला प्रोटोकॉल\nprotocol Container {\n associatedtype Item\n mutating func append(_ item: Item)\n var count: Int { get }\n}\n\n// कार्यान्वयन\nstruct IntBox: Container {\n typealias Item = Int\n private var items: [Int] = []\n mutating func append(_ item: Int) { items.append(item) }\n var count: Int { items.count }\n}\n\n// फंक्शन "some Container" लौटाता है — विशिष्ट टाइप छिपा हुआ है\nfunc makeContainer() -> some Container {\n return IntBox()\n}\n\n// उपयोग\nvar box = makeContainer()\nbox.append(42)\nprint(box.count) // 1\n\nयह दृष्टिकोण कॉलिंग कोड को बदले बिना कार्यान्वयन को लचीले ढंग से बदलने की अनुमति देता है। SwiftUI और Builder पैटर्न के संदर्भ में अक्सर यह पूछा जाता है।
\n\n3. मल्टीथ्रेडिंग: GCD और OperationQueue
\n\nGrand Central Dispatch और ऑपरेशंस का ज्ञान किसी भी iOS डेवलपर के लिए अनिवार्य है। एडवांस्ड सवाल deadlock, thread safety और प्राथमिकताओं से संबंधित होते हैं।
\n\nसवाल: अलग-अलग थ्रेड्स से साझा डेटा के साथ काम करते समय Data Race से कैसे बचें?
\n\nData Race तब होता है जब दो थ्रेड बिना सिंक्रोनाइज़ेशन के एक ही मेमोरी लोकेशन को एक साथ पढ़ते और लिखते हैं। समाधान सीरियलाइज़्ड क्यू या लॉक का उपयोग करना है।
\n\nclass ThreadSafeCounter {\n private var count = 0\n // सिंक्रोनाइज़ेशन के लिए सीरियल क्यू\n private let queue = DispatchQueue(label: "com.example.counter")\n\n func increment() {\n queue.sync {\n count += 1\n }\n }\n\n func getCount() -> Int {\n return queue.sync