क्यों "Implicitly Unwrapped Optionals" बनाएं, क्योंकि इसका मतलब है कि आपको पता है कि एक मूल्य है?


493

आप केवल एक नियमित चर या स्थिरांक बनाने के लिए "Implicitly Unwrapped Optional" क्यों बनाएंगे? यदि आप जानते हैं कि इसे सफलतापूर्वक रद्द किया जा सकता है तो पहली जगह में वैकल्पिक क्यों बनाया जाए? उदाहरण के लिए, यह क्यों है:

let someString: String! = "this is the string"

से अधिक उपयोगी होने जा रहा है:

let someString: String = "this is the string"

यदि "वैकल्पिक संकेत देते हैं कि एक स्थिर या चर को 'कोई मान नहीं है" की अनुमति है, लेकिन "कभी-कभी यह एक कार्यक्रम की संरचना से स्पष्ट होता है कि उस मूल्य के पहले सेट होने के बाद एक वैकल्पिक का हमेशा एक मूल्य होगा", का बिंदु क्या है यह पहली जगह में एक वैकल्पिक बना? यदि आपको पता है कि एक वैकल्पिक हमेशा एक मूल्य होने वाला है, तो क्या यह वैकल्पिक नहीं है?

जवाबों:


127

किसी ऐसी वस्तु के मामले पर विचार करें, जिसके निर्माण और विन्यास के दौरान शून्य गुण हो सकते हैं, लेकिन अपरिवर्तनीय और गैर-शून्य बाद में होते हैं (NSImage को अक्सर इस तरह से व्यवहार किया जाता है, हालांकि इसके मामले में यह अभी भी कभी-कभी म्यूट करने के लिए उपयोगी है)। अवैध रूप से अपरिवर्तित वैकल्पिक इसके कोड को एक अच्छा सौदा साफ कर देंगे, अपेक्षाकृत कम नुकसान के साथ (जब तक कि कोई गारंटी नहीं होगी, यह सुरक्षित होगा)।

(संपादित करें) हालांकि स्पष्ट होने के लिए: नियमित रूप से वैकल्पिक लगभग हमेशा बेहतर होते हैं।


459

इससे पहले कि मैं इम्प्लांटली अनवांटेड ऑप्शनल के लिए उपयोग के मामलों का वर्णन कर सकूं, आपको पहले से ही समझना चाहिए कि स्विफ्ट में क्या ऑप्शनल और इम्प्लांटली अनवांटेड ऑप्शनल हैं। यदि आप नहीं करते हैं, तो मैं आपको वैकल्पिक रूप से मेरा लेख पढ़ने की सलाह देता हूं

जब एक का उपयोग करने के लिए वैकल्पिक रूप से unwrapped वैकल्पिक

दो मुख्य कारण हैं कि एक इम्प्लांटली अनवांटेड वैकल्पिक का निर्माण करेगा। सभी को एक वैरिएबल को परिभाषित करने के साथ करना होगा जो कि तब कभी एक्सेस नहीं किया जाएगा nilक्योंकि अन्यथा, स्विफ्ट कंपाइलर आपको एक वैकल्पिक रूप से स्पष्ट रूप से अनप्लग करने के लिए मजबूर करेगा।

1. एक निरंतर कि शुरुआत के दौरान परिभाषित नहीं किया जा सकता है

आरम्भिक समय पूरा होने तक हर सदस्य के पास एक मूल्य होना चाहिए। कभी-कभी, स्थिरीकरण को आरंभीकरण के दौरान इसके सही मूल्य के साथ आरंभ नहीं किया जा सकता है, लेकिन इसे एक्सेस किए जाने से पहले एक मूल्य होने की गारंटी दी जा सकती है।

एक वैकल्पिक चर का उपयोग इस मुद्दे के आसपास हो जाता है क्योंकि एक वैकल्पिक स्वचालित रूप से इसके साथ आरंभिक होता है nilऔर इसमें अंत में जो मूल्य होता है वह अभी भी अपरिवर्तनीय होगा। हालाँकि, यह एक चर को लगातार अलग करने के लिए एक दर्द हो सकता है जिसे आप जानते हैं कि यह निश्चित नहीं है। अवैध रूप से अनवांटेड ऑप्शनल अतिरिक्त लाभ के साथ वैकल्पिक के रूप में एक ही लाभ प्राप्त करते हैं कि किसी को इसे हर जगह स्पष्ट रूप से खोलना नहीं पड़ता है।

इसका एक बड़ा उदाहरण यह है कि जब तक दृश्य लोड नहीं किया जाता है तब तक एक सदस्य चर को यूआईवीवाई उपवर्ग में आरंभ नहीं किया जा सकता है:

class MyView: UIView {
    @IBOutlet var button: UIButton!
    var buttonOriginalWidth: CGFloat!

    override func awakeFromNib() {
        self.buttonOriginalWidth = self.button.frame.size.width
    }
}

यहां, आप बटन की मूल चौड़ाई की गणना तब तक नहीं कर सकते, जब तक कि दृश्य लोड न हो जाए, लेकिन आप जानते हैं कि awakeFromNibदृश्य पर किसी अन्य विधि से पहले कॉल किया जाएगा (आरंभीकरण के अलावा)। मूल्य को अपनी कक्षा में स्पष्ट रूप से बिना सोचे समझे लागू करने के लिए मजबूर करने के बजाय, आप इसे अनप्लान्ड अनप्रेन्डेड वैकल्पिक के रूप में घोषित कर सकते हैं।

2. जब आपका ऐप एक परिवर्तनीय होने से पुनर्प्राप्त नहीं कर सकता है nil

यह अत्यंत दुर्लभ होना चाहिए, लेकिन यदि कोई चर nilएक्सेस होने पर आपका ऐप चलना जारी नहीं रख सकता है, तो इसके परीक्षण के लिए परेशान करना समय की बर्बादी होगी nil। आम तौर पर यदि आपके पास एक ऐसी स्थिति है जो आपके ऐप को चालू रखने के लिए बिल्कुल सही होनी चाहिए, तो आप इसका उपयोग करेंगे assert। एक अनप्लग्ड अनवैप्ड ऑप्शनल में नील के लिए एक मुखर का निर्माण किया गया है। फिर भी, वैकल्पिक को खोलना और शून्य होने पर अधिक वर्णनात्मक मुखर का उपयोग करना अक्सर अच्छा होता है।

जब एक का उपयोग नहीं करने के लिए अवैध रूप से वैकल्पिक खोल दिया

1. लज़ीज़ परिकलित सदस्य चर

कभी-कभी आपके पास एक सदस्य चर होता है जिसे कभी भी शून्य नहीं होना चाहिए, लेकिन इसे आरंभीकरण के दौरान सही मान पर सेट नहीं किया जा सकता है। एक समाधान के लिए एक अनप्लग्ड अनवाप्लेटेड वैकल्पिक का उपयोग करना है, लेकिन एक बेहतर तरीका एक आलसी चर का उपयोग करना है:

class FileSystemItem {
}

class Directory : FileSystemItem {
    lazy var contents : [FileSystemItem] = {
        var loadedContents = [FileSystemItem]()
        // load contents and append to loadedContents
        return loadedContents
    }()
}

अब, सदस्य चर contentsको तब तक इनिशियलाइज़ नहीं किया जाता है जब तक वह पहली बार एक्सेस नहीं हो जाता है। इससे वर्ग को प्रारंभिक मूल्य की गणना करने से पहले सही स्थिति में आने का मौका मिलता है।

नोट: यह ऊपर से # 1 विरोधाभास लग सकता है। हालाँकि, एक महत्वपूर्ण अंतर है। buttonOriginalWidthऊपर बदलने से पहले संपत्ति पर पहुंचने पर बटन चौड़ाई किसी को रोकने के लिए viewDidLoad के दौरान सेट किया जाना चाहिए।

2. हर जगह एल्स

अधिकांश भाग के लिए, अनप्लग किए गए अनवांटेड ऑप्शनल को टाला जाना चाहिए क्योंकि यदि गलती से उपयोग किया जाता है, तो यह एक्सेस करते समय आपका पूरा ऐप क्रैश हो जाएगा nil। यदि आप कभी इस बारे में निश्चित नहीं हैं कि क्या एक चर शून्य हो सकता है, हमेशा एक सामान्य वैकल्पिक का उपयोग करने के लिए डिफ़ॉल्ट। एक चर है कि nilनिश्चित रूप से कभी नहीं होता है बहुत ज्यादा चोट नहीं करता है।


4
इस उत्तर को बीटा 5 के लिए अपडेट किया जाना चाहिए। आप अब उपयोग नहीं कर सकते if someOptional
सांता क्लॉज

2
@SantaClaus hasValueको वैकल्पिक पर सही परिभाषित किया गया है। मैं hasValueउन लोगों के शब्दार्थ को पसंद करता हूं != nil। मुझे लगता है कि यह नए प्रोग्रामरों के लिए बहुत अधिक समझने योग्य है, जिन्होंने nilअन्य भाषाओं में उपयोग नहीं किया है। hasValueकी तुलना में बहुत अधिक तार्किक है nil
दशहरा

2
ऐसा लगता है कि hasValueबीटा 6 से खींचा गया था। ऐश ने इसे वापस रखा हालांकि ... github.com/AshFurrow/hasValue
क्रिस वैगनर

1
@newacct ओबजैक इनिशियलाइज़र्स के रिटर्न प्रकार के बारे में, यह एक निहित इम्प्लांटिकली अनवांटेड वैकल्पिक है। "गैर-वैकल्पिक" का उपयोग करने के लिए आपके द्वारा वर्णित व्यवहार ठीक वैसा ही है जैसा कि एक अनप्लान्ड अनप्रेन्डेड वैकल्पिक वैकल्पिक होगा (एक्सेस किए जाने तक विफल नहीं)। जबरन अलिखित करके कार्यक्रम को पहले विफल होने देने के बारे में, मैं मानता हूं कि गैर-वैकल्पिक का उपयोग करना पसंद है, लेकिन यह हमेशा संभव नहीं है।
18

1
@confile नं। कोई बात नहीं, यह ऑब्जेक्टिव-सी में एक पॉइंटर के रूप में दिखाई देने वाला है (यदि यह वैकल्पिक, अंतर्निहित रूप से अपरिवर्तित, या गैर-वैकल्पिक हो)।
drewag

56

गैर-वैकल्पिक के रूप में किसी संपत्ति को प्रस्तुत करने के लिए अवैध रूप से अपरिवर्तित वैकल्पिक उपयोगी होते हैं जब वास्तव में कवर के तहत वैकल्पिक होने की आवश्यकता होती है। यह दो संबंधित वस्तुओं के बीच "गाँठ बांधने" के लिए अक्सर आवश्यक होता है कि प्रत्येक को दूसरे के संदर्भ की आवश्यकता होती है। यह समझ में आता है जब न तो संदर्भ वास्तव में वैकल्पिक है, लेकिन उनमें से एक को शून्य होने की आवश्यकता है जबकि जोड़ी को इनिशियलाइज़ किया जा रहा है।

उदाहरण के लिए:

// These classes are buddies that never go anywhere without each other
class B {
    var name : String
    weak var myBuddyA : A!
    init(name : String) {
        self.name = name
    }
}

class A {
    var name : String
    var myBuddyB : B
    init(name : String) {
        self.name = name
        myBuddyB = B(name:"\(name)'s buddy B")
        myBuddyB.myBuddyA = self
    }
}

var a = A(name:"Big A")
println(a.myBuddyB.name)   // prints "Big A's buddy B"

किसी भी Bउदाहरण में हमेशा एक वैध myBuddyAसंदर्भ होना चाहिए , इसलिए हम उपयोगकर्ता को इसे वैकल्पिक नहीं बनाना चाहते हैं, लेकिन हमें इसे वैकल्पिक बनाने की आवश्यकता है ताकि हम इसका उल्लेख करने से Bपहले एक निर्माण कर सकें A

तथापि! इस तरह की पारस्परिक संदर्भ आवश्यकता अक्सर तंग युग्मन और खराब डिजाइन का संकेत है। यदि आप अपने आप को अंतर्निहित रूप से अपरिवर्तित वैकल्पिकों पर भरोसा करते हुए पाते हैं, तो आपको संभवतः क्रॉस-निर्भरता को खत्म करने के लिए रीफैक्टरिंग पर विचार करना चाहिए।


7
मुझे लगता है कि इस भाषा की विशेषता के कारण का एक कारण है@IBOutlet
जियाओ

11
"होवर" कैविएट के लिए +1। यह हर समय सच नहीं हो सकता है, लेकिन यह निश्चित रूप से कुछ के लिए बाहर देखने के लिए है।
जेएमडी

4
आपके पास अभी भी ए और बी के बीच एक मजबूत संदर्भ चक्र है। गैरकानूनी रूप से अपरिवर्तित वैकल्पिक एक कमजोर संदर्भ नहीं बनाते हैं। आपको अभी भी myByddyA या myBuddyB को कमज़ोर (शायद myBuddyA) घोषित करने की आवश्यकता है
drewag

6
यह उत्तर गलत और खतरनाक रूप से भ्रामक क्यों है, इससे भी अधिक स्पष्ट होने के लिए: अस्पष्ट रूप से अनचाहे विकल्प में स्मृति प्रबंधन के साथ कोई लेना- देना नहीं है और चक्र को बनाए रखने से रोकना नहीं है। हालांकि, दो तरह के संदर्भ को स्थापित करने के लिए वर्णित परिस्थिति में अभी भी अनप्लग किए गए वैकल्पिक विकल्प उपयोगी हैं। तो बस weakघोषणा को जोड़ने और "एक मजबूत बनाए रखने के चक्र को बनाए बिना" को हटा दें
drewag

1
@ ड्रग: आप सही कह रहे हैं - मैंने रिटेक चक्र को हटाने के लिए उत्तर को संपादित किया है। मेरा इरादा पिछड़ेपन को कमजोर बनाने का था लेकिन मुझे लगता है कि इससे मेरा दिमाग फिसल गया।
n8gray

37

अवैध रूप से अपरिवर्तित वैकल्पिक हाइब्रिड वातावरण में काम करने के लिए व्यावहारिक समझौता है जो मौजूदा कोको फ्रेमवर्क और उनके सम्मेलनों के साथ अधिक सुखद होता है, जबकि स्विफ्ट कंपाइलर द्वारा लागू - शून्य बिंदुओं के बिना - सुरक्षित प्रोग्रामिंग प्रतिमान में सौतेला व्यवहार प्रवास की अनुमति देता है।

द बेसिक्स चैप्टर में स्विफ्ट बुक, सेक्शन इम्प्लांटली अनप्रेडेड ऑप्शन्स कहते हैं:

वैकल्पिक रूप से अपरिवर्तित वैकल्पिक तब उपयोगी होते हैं जब वैकल्पिक का मूल्य पहले परिभाषित किए जाने के तुरंत बाद मौजूद होने की पुष्टि की जाती है और उसके बाद निश्चित रूप से हर बिंदु पर मौजूद होने का अनुमान लगाया जा सकता है। स्विफ्ट में अंतर्निहित अलिखित वैकल्पिक का प्राथमिक उपयोग क्लास इनिशियलाइज़ेशन के रूप में है, जैसा कि अज्ञात सन्दर्भों में वर्णित है और इम्प्लांटिकली अनवैक्ड ऑप्शनल प्रॉपर्टीज़ में वर्णित है ।
...
आप एक अंतर्निहित अलिखित वैकल्पिक के बारे में सोच सकते हैं कि जब भी इसका उपयोग किया जाता है तो वैकल्पिक रूप से अलिखित होने की अनुमति देना। प्रत्येक बार जब आप इसका उपयोग करते हैं तो वैकल्पिक नाम के बाद एक विस्मयादिबोधक चिह्न रखने के बजाय, आप इसे घोषित करते समय वैकल्पिक के प्रकार के बाद विस्मयादिबोधक चिह्न लगाते हैं।

इस मामले हैं, जहां का उपयोग करने के नीचे आता है गैर nil-नेस गुणों का उपयोग सम्मेलन के माध्यम से स्थापित किया गया है, और वर्ग प्रारंभ दौरान संकलक द्वारा लागू नहीं की जा सकती है। उदाहरण के लिए, ऐसे UIViewControllerगुण जो एनआईबी या स्टोरीबोर्ड से आरंभीकृत किए जाते हैं, जहाँ प्रारंभिककरण को अलग-अलग चरणों में विभाजित किया जाता है, लेकिन viewDidLoad()आप यह मान सकते हैं कि आम तौर पर गुण मौजूद हैं। अन्यथा, संकलक को संतुष्ट करने के लिए, आपको कोड के मुख्य उद्देश्य को अस्पष्ट करने के लिए केवल मजबूर अलिखित , वैकल्पिक बाध्यकारी या वैकल्पिक श्रृंखलन का उपयोग करना होगा ।

स्विफ्ट पुस्तक से ऊपर का हिस्सा स्वचालित संदर्भ गणना अध्याय को भी संदर्भित करता है :

हालांकि, एक तीसरा परिदृश्य है, जिसमें दोनों गुणों का हमेशा एक मूल्य होना चाहिए, और न ही संपत्ति कभी भी nilएक बार प्रारंभिक होने के बाद पूरी होनी चाहिए । इस परिदृश्य में, एक वर्ग पर एक अज्ञात संपत्ति को अन्य वर्ग पर एक अंतर्निहित अलिखित वैकल्पिक संपत्ति के साथ जोड़ना उपयोगी है।

यह दोनों गुणों को एक बार आरंभीकरण चक्र से बचने के दौरान, एक बार आरंभीकरण पूरा होने के बाद (वैकल्पिक अलिखित बिना) सीधे पहुँचा जा सकता है।

यह कचरा एकत्र करने वाली भाषा नहीं होने की खामियों के लिए आता है, इसलिए एक चक्र के रूप में आप पर बरकरार चक्रों का टूटना आपके लिए है और अंतर्निहित अलिखित वैकल्पिक इस quirk को छिपाने के लिए एक उपकरण है।

यह "आपके कोड में अंतर्निहित अलिखित वैकल्पिक का उपयोग कब करें?" सवाल। एक एप्लिकेशन डेवलपर के रूप में, आप ज्यादातर उन्हें ऑब्जेक्टिव-सी में लिखे गए पुस्तकालयों के विधि हस्ताक्षर में सामना करेंगे, जिसमें वैकल्पिक प्रकारों को व्यक्त करने की क्षमता नहीं है।

कोको और उद्देश्य-सी के साथ स्विफ्ट का उपयोग करने से , शून्य के साथ काम करना :

क्योंकि Objective-C कोई गारंटी नहीं देता है कि कोई ऑब्जेक्ट नॉन-नील है, Swift तर्क प्रकारों में सभी वर्गों को बनाता है और आयातित Object-C API में वैकल्पिक प्रकार लौटाता है। ऑब्जेक्ट-सी ऑब्जेक्ट का उपयोग करने से पहले, आपको यह सुनिश्चित करने के लिए जाँच करनी चाहिए कि वह गायब नहीं है।

कुछ मामलों में, आप पूरी तरह से निश्चित हो सकते हैं कि एक उद्देश्य-सी विधि या संपत्ति एक nilवस्तु संदर्भ नहीं देती है। इस विशेष परिदृश्य में वस्तुओं को काम करने के लिए सुविधाजनक बनाने के लिए, स्विफ्ट आयात प्रकारों को अंतर्निहित अलिखित वैकल्पिक के रूप में आयात करता है । वैकल्पिक रूप से अपरिवर्तित वैकल्पिक प्रकारों में वैकल्पिक प्रकारों की सभी सुरक्षा विशेषताएं शामिल होती हैं। इसके अलावा, आप चेक किए बिना सीधे मान तक पहुंच सकते हैंnilया खुद को अलिखित करना। जब आप इस प्रकार के वैकल्पिक प्रकार में मूल्य को सुरक्षित रूप से पहले से अलग किए बिना उपयोग करते हैं, तो अनुमानित रूप से अपरिवर्तित वैकल्पिक जांचें कि क्या मूल्य गायब है। यदि मान अनुपलब्ध है, तो रनटाइम त्रुटि होती है। नतीजतन, आपको हमेशा अपने आप को एक अंतर्निहित अलिखित वैकल्पिक जांचना और खोलना चाहिए, जब तक कि आप सुनिश्चित न हों कि मूल्य गायब नहीं हो सकता है।

... और यहाँ से परे है ड्रेगन


इस गहन उत्तर के लिए धन्यवाद। क्या आप किसी त्वरित अनचाहे विकल्प का उपयोग करने की एक त्वरित जाँच सूची के बारे में सोच सकते हैं और जब एक मानक चर पर्याप्त होगा?
बालगामी_मास्टर

@Hairgami_Master मैंने एक सूची और ठोस उदाहरणों के साथ अपना जवाब जोड़ा
Drewag

18

एक-लाइन (या कई-लाइन) सरल उदाहरण वैकल्पिक के व्यवहार को बहुत अच्छी तरह से कवर नहीं करते हैं - हाँ, यदि आप एक चर घोषित करते हैं और इसे तुरंत मूल्य प्रदान करते हैं, तो वैकल्पिक में कोई मतलब नहीं है।

अब तक मैंने देखा कि सबसे अच्छा मामला सेटअप है जो ऑब्जेक्ट इनिशियलाइज़ेशन के बाद होता है, इसके बाद उस सेटअप का अनुसरण करने के लिए "गारंटी" का उपयोग होता है, उदाहरण के लिए व्यू कंट्रोलर में:

class MyViewController: UIViewController {

    var screenSize: CGSize?

    override func viewDidLoad {
        super.viewDidLoad()
        screenSize = view.frame.size
    }

    @IBAction printSize(sender: UIButton) {
        println("Screen size: \(screenSize!)")
    }
}

printSizeदृश्य लोड होने के बाद हमें पता चलेगा - यह उस दृश्य के अंदर नियंत्रण के लिए झुकी हुई एक क्रिया विधि है, और हमने इसे अन्यथा नहीं कॉल करने के लिए सुनिश्चित किया है। तो हम अपने आप को कुछ वैकल्पिक जाँच / बंधन से बचा सकते हैं !। स्विफ्ट उस गारंटी को नहीं पहचान सकती है (कम से कम जब तक ऐप्पल को रोकने की समस्या हल नहीं होती है), इसलिए आप संकलक को बताएं कि यह मौजूद है।

यह कुछ हद तक सुरक्षा को तोड़ता है, हालांकि। कहीं भी आपके पास एक अंतर्निहित अलिखित वैकल्पिक है एक जगह है जहां आपका ऐप क्रैश हो सकता है यदि आपकी "गारंटी" हमेशा पकड़ में नहीं आती है, इसलिए यह संयम का उपयोग करने की सुविधा है। इसके अलावा, !हर समय उपयोग करने से यह लगता है कि आप चिल्ला रहे हैं, और किसी को भी पसंद नहीं है।


क्यों न केवल इनिशियलाइज़ स्क्रीन को CGSize (ऊंचाई: 0, चौड़ाई: 0) के रूप में सेट करें और हर बार जब आप इसे एक्सेस करते हैं तो वेरिएबल को चिल्लाने की परेशानी से बचाएं?
मार्टिन गॉर्डन

एक आकार सबसे अच्छा उदाहरण नहीं हो सकता है, क्योंकि CGSizeZeroवास्तविक दुनिया के उपयोग में एक अच्छा प्रहरी मूल्य हो सकता है। लेकिन क्या होगा यदि आपके पास निब से भरा हुआ आकार है जो वास्तव में शून्य हो सकता है? फिर CGSizeZeroएक प्रहरी के रूप में उपयोग करने से आपको एक मूल्य के बीच अंतर होने और शून्य पर सेट होने में अंतर करने में मदद नहीं मिलती है। इसके अलावा, यह निब (या उसके बाद कहीं और init) से लोड किए गए अन्य प्रकारों पर भी समान रूप से लागू होता है : स्ट्रिंग्स,
साक्षात्कारों के

2
कार्यात्मक भाषाओं में वैकल्पिक के बिंदु का हिस्सा प्रहरी मान नहीं है। आपके पास या तो मूल्य है या आप नहीं हैं। आपके पास एक ऐसा मामला नहीं होना चाहिए जहां आपके पास एक मूल्य है जो एक लापता मूल्य को इंगित करता है।
वेन टान्नर

4
मुझे लगता है कि आपने ओपी के सवाल को गलत समझा है। ओपी वैकल्पिक के लिए सामान्य मामले के बारे में नहीं पूछ रहा है, बल्कि विशेष रूप से अंतर्निहित अलिखित वैकल्पिक की आवश्यकता / उपयोग के बारे में पूछ रहा है (अर्थात let foo? = 42, नहीं let foo! = 42)। यह पता नहीं है। (यह वैकल्पिक के बारे में एक प्रासंगिक उत्तर हो सकता है, आप मन लगा सकते हैं, लेकिन अंतर्निहित अलिखित वैकल्पिक के बारे में नहीं जो एक अलग / संबंधित जानवर हैं।)
जेएमडी

15

Apple द स्विफ्ट प्रोग्रामिंग लैंग्वेज में एक बेहतरीन उदाहरण देता है -> ऑटोमैटिक रेफरेंस काउंटिंग -> क्लास इंस्टेंस के बीच मजबूत रेफरेंस साइकल को हल करना -> अज्ञात संदर्भ और अनप्लग्ड अल्टरनेटिव प्रॉपर्टीज

class Country {
    let name: String
    var capitalCity: City! // Apple finally correct this line until 2.0 Prerelease (let -> var)
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

के लिए initializer के लिए initializer के Cityभीतर से बुलाया है Country। हालाँकि, एक नया उदाहरण पूरी तरह से प्रारंभिक होने तक इनिशियलाइज़र को Countryपास नहीं किया जा सकता है, जैसा कि टू-फेज़ इनिशियलाइज़ेशन में वर्णित है ।selfCityCountry

इस आवश्यकता से निपटने के लिए, आप capitalCityसंपत्ति Countryको एक अनुमानित रूप से अपरिवर्तित वैकल्पिक संपत्ति घोषित करते हैं।


इस उत्तर में उल्लिखित ट्यूटोरियल यहाँ है
फ्रेंकलिन यू

3

निहित विकल्पों के औचित्य को पहले स्पष्ट रूप से अपरिवर्तित करने के औचित्य को देखकर समझाना आसान है।

एक वैकल्पिक (जबरन या नहीं), का उपयोग करते हुए मजबूर करना! ऑपरेटर, का अर्थ है कि आप निश्चित हैं कि आपके कोड में कोई बग नहीं है और वैकल्पिक में पहले से ही एक मूल्य है जहां इसे अलिखित किया जा रहा है। के बिना ! ऑपरेटर, आप संभवतः एक वैकल्पिक बंधन के साथ दावा करेंगे:

 if let value = optionalWhichTotallyHasAValue {
     println("\(value)")
 } else {
     assert(false)
 }

जो उतना अच्छा नहीं है

println("\(value!)")

अब, निहित विकल्प आपको एक ऐसा विकल्प प्रदान करने की अनुमति देते हैं, जिसकी उम्मीद आपको हमेशा तब होती है जब सभी संभावित प्रवाह में, अलिखित होने पर एक मूल्य हो। तो यह सिर्फ आपकी मदद करने में एक कदम आगे जाता है - लिखने की आवश्यकता को आराम देकर! प्रत्येक बार अनचाहे, और यह सुनिश्चित करने के लिए कि प्रवाह के बारे में आपकी धारणा गलत है, तो रनटाइम अभी भी त्रुटि करेगा।


1
@newacct: आपके कोड के माध्यम से सभी संभावित प्रवाह में गैर-शून्य, अभिभावक के माध्यम से अभिभावक (वर्ग / संरचना) के प्रारंभ से गैर-शून्य के समान नहीं है। इंटरफ़ेस बिल्डर क्लासिक उदाहरण है (लेकिन कई अन्य आरंभीकृत आरंभीकरण पैटर्न हैं): यदि कोई वर्ग केवल एक नीब से कभी भी उपयोग किया जाता है, तो आउटलेट चर सेट नहीं किए जाएंगे init(जो कि आप भी लागू नहीं कर सकते हैं), लेकिन वे ' फिर इसकी गारंटी के बाद स्थापित किया जाना awakeFromNib/ viewDidLoad
rickster

3

यदि आप निश्चित रूप से जानते हैं, तो इसके बजाय एक वैकल्पिक से एक मूल्य वापसी nil, Implicitly Unwrapped Optionals सीधे उन मानों को वैकल्पिक और गैर वैकल्पिक से पकड़ने के लिए उपयोग नहीं कर सकते।

//Optional string with a value
let optionalString: String? = "This is an optional String"

//Declaration of an Implicitly Unwrapped Optional String
let implicitlyUnwrappedOptionalString: String!

//Declaration of a non Optional String
let nonOptionalString: String

//Here you can catch the value of an optional
implicitlyUnwrappedOptionalString = optionalString

//Here you can't catch the value of an optional and this will cause an error
nonOptionalString = optionalString

तो यह उपयोग के बीच का अंतर है

let someString : String! तथा let someString : String


1
यह ओपी के सवाल का जवाब नहीं देता है। ओपी जानता है कि एक अनप्लग्ड अनप्रेस्ड ऑप्शनल क्या है।
फ्रैंकलिन यू

0

मुझे लगता Optionalहै कि इस निर्माण के लिए एक बुरा नाम है जो बहुत से शुरुआती लोगों को भ्रमित करता है।

अन्य भाषाओं (उदाहरण के लिए कोटलिन और सी #) शब्द का उपयोग करते हैं Nullable, और यह इसे समझने में बहुत आसान बनाता है।

Nullableइसका मतलब है कि आप इस प्रकार के एक चर के लिए एक शून्य मान प्रदान कर सकते हैं। तो अगर यह है Nullable<SomeClassType>, तो आप इसे nulls असाइन कर सकते हैं, अगर यह सिर्फ है SomeClassType, तो आप नहीं कर सकते। बस इसी तरह स्विफ्ट काम करती है।

उनका उपयोग क्यों करें? ठीक है, कभी-कभी आपको नल की आवश्यकता होती है, इसीलिए। उदाहरण के लिए, जब आप जानते हैं कि आप एक कक्षा में एक क्षेत्र रखना चाहते हैं, लेकिन जब आप उस वर्ग का एक उदाहरण बना रहे हैं, तो आप उसे कुछ भी निर्दिष्ट नहीं कर सकते हैं, लेकिन आप बाद में उस पर काम करेंगे। मैं उदाहरण नहीं दूंगा, क्योंकि लोगों ने पहले ही उन्हें यहां उपलब्ध कराया है। मैं सिर्फ अपने 2 सेंट देने के लिए इसे लिख रहा हूं।

Btw, मेरा सुझाव है कि आप यह देखें कि यह अन्य भाषाओं में कैसे काम करता है, जैसे कोटलिन और सी #।

यहाँ कोटलिन में इस सुविधा को समझाने वाला एक लिंक दिया गया है: https://kotlinlang.org/docs/reference/null-safety.html

जावा और स्काला जैसी अन्य भाषाएं हैं, Optionalलेकिन वे Optionalस्विफ्ट में एस से अलग तरीके से काम करते हैं , क्योंकि जावा और स्काला के प्रकार डिफ़ॉल्ट रूप से सभी अशक्त हैं।

सब के सब, मुझे लगता है कि इस सुविधा का नाम Nullableस्विफ्ट में होना चाहिए था , न कि Optional...


0

Implicitly Unwrapped Optionalके लिए एक वाक्य रचना चीनी है Optionalकि एक प्रोग्रामर को एक चर को खोलने के लिए मजबूर नहीं करता है। यह एक चर के दौरान जो initialised नहीं किया जा सकता के लिए इस्तेमाल किया जा सकता two-phase initialization processहै और अर्थ है गैर शून्य। यह चर खुद को गैर-शून्य के रूप में व्यवहार करता है लेकिन वास्तव में एक वैकल्पिक चर है। एक अच्छा उदाहरण है - इंटरफ़ेस बिल्डर के आउटलेट

Optional आमतौर पर बेहतर हैं

var nonNil: String = ""
var optional: String?
var implicitlyUnwrappedOptional: String!

func foo() {
    //get a value
    nonNil.count
    optional?.count

    //Danderour - makes a force unwrapping which can throw a runtime error
    implicitlyUnwrappedOptional.count

    //assign to nil
//        nonNil = nil //Compile error - 'nil' cannot be assigned to type 'String'
    optional = nil
    implicitlyUnwrappedOptional = nil
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.