क्या है "घातक त्रुटि: एक वैकल्पिक मूल्य को उजागर करते समय अप्रत्याशित रूप से शून्य पाया जाता है" का मतलब है?
मेरा स्विफ्ट कार्यक्रम EXC_BAD_INSTRUCTION
निम्नलिखित समान त्रुटियों में से एक के साथ दुर्घटनाग्रस्त हो रहा है । इस त्रुटि का क्या मतलब है, और मैं इसे कैसे ठीक करूं?
घातक त्रुटि: वैकल्पिक मूल्य को खोलते समय अनपेक्षित रूप से शून्य पाया गया
या
घातक त्रुटि: एक वैकल्पिक मान को स्पष्ट करते हुए अप्रत्याशित रूप से शून्य पाया गया
इस पोस्ट का उद्देश्य "अप्रत्याशित रूप से पाए गए नील" मुद्दों के उत्तर एकत्र करना है, ताकि वे बिखरे और खोजने में कठिन न हों। अपने स्वयं के उत्तर को जोड़ने या मौजूदा विकी उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें ।
जवाब
यह उत्तर सामुदायिक विकि है । यदि आपको लगता है कि इसे बेहतर बनाया जा सकता है, तो इसे संपादित करने के लिए स्वतंत्र महसूस करें !
पृष्ठभूमि: एक वैकल्पिक क्या है?
स्विफ्ट में, Optional<Wrapped>
एक विकल्प प्रकार है : इसमें मूल ("रैप्ड") प्रकार से कोई भी मान शामिल हो सकता है, या बिल्कुल भी कोई मूल्य नहीं हो सकता है (विशेष मूल्य nil
)। एक वैकल्पिक मूल्य का उपयोग किए जाने से पहले अपरिवर्तित होना चाहिए ।
वैकल्पिक एक सामान्य प्रकार है , जिसका अर्थ है कि Optional<Int>
और Optional<String>
विशिष्ट प्रकार हैं - अंदर के प्रकार <>
को रैप्ड प्रकार कहा जाता है। हुड के तहत, एक वैकल्पिक दो मामलों के साथ एक एनम है : .some(Wrapped)
और .none
, जहां .none
के बराबर है nil
।
नाम के प्रकार का उपयोग करके वैकल्पिक घोषित किया जा सकता है Optional<T>
, या (आमतौर पर) ?
प्रत्यय के साथ शॉर्टहैंड के रूप में ।
var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int? // `nil` is the default when no value is provided
var aVerboseOptionalInt: Optional<Int> // equivalent to `Int?`
anOptionalInt = nil // now this variable contains nil instead of an integer
कोड लिखते समय अपनी मान्यताओं को व्यक्त करने के लिए वैकल्पिक एक सरल लेकिन शक्तिशाली उपकरण है। कंपाइलर इस जानकारी का उपयोग आपको गलतियाँ करने से रोकने के लिए कर सकता है। से स्विफ्ट प्रोग्रामिंग भाषा :
स्विफ्ट एक प्रकार की सुरक्षित भाषा है, जिसका अर्थ है कि भाषा आपको उन मूल्यों के बारे में स्पष्ट होने में मदद करती है जो आपके कोड के साथ काम कर सकते हैं। यदि आपके कोड के भाग को एक की आवश्यकता है
String
, तो टाइप सुरक्षा आपको इसेInt
गलती से पारित करने से रोकती है। इसी तरह, टाइप सेफ्टी आपको गलती से वैकल्पिकString
को कोड के एक टुकड़े से गुजरने से रोकती है जिसके लिए गैर-वैकल्पिक की आवश्यकता होती हैString
। प्रकार की सुरक्षा आपको विकास प्रक्रिया में त्रुटियों को जल्द से जल्द पकड़ने और ठीक करने में मदद करती है।
कुछ अन्य प्रोग्रामिंग भाषाओं में जेनेरिक विकल्प प्रकार भी होते हैं : उदाहरण के लिए, शायद हास्केल में, रस्ट में विकल्प , और सी ++ 17 में वैकल्पिक ।
विकल्प प्रकार के बिना प्रोग्रामिंग भाषाओं में , एक विशेष "प्रहरी" मूल्य का उपयोग अक्सर एक वैध मूल्य की अनुपस्थिति को इंगित करने के लिए किया जाता है। उद्देश्य-सी में, उदाहरण के लिए, nil
( अशक्त सूचक ) किसी वस्तु की कमी को दर्शाता है। जैसे आदिम प्रकार के लिए int
, एक अशक्त सूचक, नहीं किया जा सकता है ताकि आप या तो एक अलग चर (जैसे की आवश्यकता होगी value: Int
और isValid: Bool
) या एक नामित प्रहरी मूल्य (जैसे -1
या INT_MIN
)। ये दृष्टिकोण त्रुटि-प्रवण हैं क्योंकि isValid
चेक को भेजना या प्रहरी मूल्य के लिए जांचना आसान है । इसके अलावा, अगर किसी विशेष मूल्य को प्रहरी के रूप में चुना जाता है, तो इसका मतलब है कि इसे अब वैध मूल्य के रूप में नहीं माना जा सकता है ।
विकल्प जैसे कि स्विफ्ट Optional
इन समस्याओं को एक विशेष, अलग nil
मूल्य (इसलिए आपको एक सेंटिनल मूल्य को नामित करने की आवश्यकता नहीं है) को हल करके , और मजबूत प्रकार की प्रणाली का लाभ उठाकर ताकि संकलक आपको आवश्यक होने पर शून्य की जांच करने में याद रखने में मदद कर सके।
मुझे एक वैकल्पिक मूल्य को उजागर करते समय " घातक त्रुटि: अप्रत्याशित रूप से शून्य क्यों मिला ?"
वैकल्पिक मूल्य तक पहुँचने के लिए (यदि यह एक है), तो आपको इसे खोलना होगा। एक वैकल्पिक मूल्य सुरक्षित रूप से या जबरन हटाया जा सकता है। यदि आप एक वैकल्पिक को बल देते हैं, और इसका कोई मूल्य नहीं है, तो आपका कार्यक्रम उपरोक्त संदेश के साथ क्रैश हो जाएगा।
कोड की एक पंक्ति को उजागर करके Xcode आपको दुर्घटना दिखाएगा। इस लाइन पर समस्या होती है।
यह दुर्घटना दो अलग-अलग प्रकार के फोर्स-अनप्रैप के साथ हो सकती है:
1. स्पष्ट बल खोलना
यह !
एक वैकल्पिक पर ऑपरेटर के साथ किया जाता है । उदाहरण के लिए:
let anOptionalString: String?
print(anOptionalString!) // <- CRASH
घातक त्रुटि: वैकल्पिक मूल्य को खोलते समय अनपेक्षित रूप से शून्य पाया गया
जैसा anOptionalString
कि nil
यहां है, आपको उस लाइन पर एक दुर्घटना मिलेगी जहां आप इसे खोलते हैं।
2. अवैध रूप से अनचाहे वैकल्पिक
इन्हें एक प्रकार के !
बजाय एक के साथ परिभाषित किया ?
गया है।
var optionalDouble: Double! // this value is implicitly unwrapped wherever it's used
इन वैकल्पिकों को एक मान माना जाता है। इसलिए जब भी आप एक अंतर्निहित अलिखित वैकल्पिक का उपयोग करते हैं, तो यह स्वचालित रूप से आपके लिए अपरिवर्तित हो जाएगा। यदि इसमें कोई मान नहीं है, तो यह क्रैश हो जाएगा।
print(optionalDouble) // <- CRASH
घातक त्रुटि: एक वैकल्पिक मान को स्पष्ट करते हुए अप्रत्याशित रूप से शून्य पाया गया
यह सुनिश्चित करने के लिए कि क्रैश किस चर का कारण है, आप ⌥परिभाषा दिखाने के लिए क्लिक करते समय पकड़ सकते हैं , जहाँ आपको वैकल्पिक प्रकार मिल सकता है।
IBOutlets, विशेष रूप से, आमतौर पर अंतर्निहित अलिखित वैकल्पिक हैं। ऐसा इसलिए है क्योंकि आपका xib या स्टोरीबोर्ड प्रारंभ के बाद , रनटाइम पर आउटलेट को लिंक करेगा । इसलिए आपको यह सुनिश्चित करना चाहिए कि आपके द्वारा लोड किए जाने से पहले आप आउटलेट्स तक नहीं पहुंच रहे हैं। आपको यह भी जांचना चाहिए कि कनेक्शन आपके स्टोरीबोर्ड / xib फ़ाइल में सही हैं, अन्यथा मान nil
रनटाइम पर होंगे , और इसलिए जब वे अंतर्निहित होते हैं तो दुर्घटनाग्रस्त हो जाते हैं । कनेक्शन ठीक करते समय, अपने आउटलेट को परिभाषित करने वाले कोड की पंक्तियों को हटाने का प्रयास करें, फिर उन्हें फिर से कनेक्ट करें।
जब मैं एक वैकल्पिक खोलना कभी मजबूर करना चाहिए?
स्पष्ट बल खोलना
एक सामान्य नियम के रूप में, आपको कभी भी !
ऑपरेटर के साथ वैकल्पिक रूप से अनट्रैप करने के लिए मजबूर नहीं करना चाहिए । ऐसे मामले हो सकते हैं जहां उपयोग !
करना स्वीकार्य है - लेकिन आपको केवल इसका उपयोग करना चाहिए यदि आप 100% सुनिश्चित हैं कि वैकल्पिक में एक मूल्य है।
जबकि एक ऐसा अवसर हो सकता है जहां आप बल प्रयोग को समाप्त कर सकते हैं, जैसा कि आप इस तथ्य के लिए जानते हैं कि एक वैकल्पिक में एक मान होता है - एक जगह नहीं है जहां आप सुरक्षित रूप से उस वैकल्पिक को खोल नहीं सकते।
अवैध रूप से अनचाहे वैकल्पिक
ये चर ऐसे डिज़ाइन किए गए हैं कि आप अपने कोड में बाद तक उनके असाइनमेंट को स्थगित कर सकते हैं। यह है अपने सुनिश्चित करने के लिए वे एक मूल्य है इससे पहले कि आप उन तक पहुँच जिम्मेदारी। हालाँकि, क्योंकि उनमें बल प्रयोग शामिल नहीं है, फिर भी वे स्वाभाविक रूप से असुरक्षित हैं - क्योंकि वे मान लेते हैं कि आपका मूल्य गैर-शून्य है, भले ही शून्य असाइन करना मान्य है।
आपको अंतिम उपाय के रूप में केवल अंतर्निहित अलिखित वैकल्पिक का उपयोग करना चाहिए । यदि आप एक आलसी चर का उपयोग कर सकते हैं , या एक चर के लिए एक डिफ़ॉल्ट मान प्रदान कर सकते हैं - तो आपको एक अनुमानित रूप से अवांछित वैकल्पिक का उपयोग करने के बजाय ऐसा करना चाहिए।
हालाँकि, कुछ परिदृश्य हैं जहाँ अंतर्निहित अलिखित वैकल्पिक लाभकारी हैं , और आप अभी भी नीचे सूचीबद्ध के रूप में उन्हें सुरक्षित रूप से अलग करने के विभिन्न तरीकों का उपयोग करने में सक्षम हैं - लेकिन आपको हमेशा सावधानी के साथ उनका उपयोग करना चाहिए ।
मैं वैकल्पिक रूप से कैसे निपट सकता हूं?
यह जांचने का सबसे सरल तरीका है कि वैकल्पिक में कोई मान है या नहीं, इसकी तुलना करना है nil
।
if anOptionalInt != nil {
print("Contains a value!")
} else {
print("Doesn’t contain a value.")
}
हालांकि, 99.9% समय जब वैकल्पिक के साथ काम करते हैं, तो आप वास्तव में इसके मूल्य को एक्सेस करना चाहते हैं, अगर इसमें एक भी शामिल हो। ऐसा करने के लिए, आप वैकल्पिक बाइंडिंग का उपयोग कर सकते हैं ।
वैकल्पिक बंधन
वैकल्पिक बाइंडिंग आपको यह जांचने की अनुमति देती है कि क्या वैकल्पिक में कोई मान है - और आपको किसी नए चर या स्थिर पर अलिखित मान असाइन करने की अनुमति देता है। यह सिंटैक्स का उपयोग करता है if let x = anOptional {...}
या if var x = anOptional {...}
, यदि आपको इसे बाध्य करने के बाद नए चर के मूल्य को संशोधित करने की आवश्यकता है, तो निर्भर करता है।
उदाहरण के लिए:
if let number = anOptionalInt {
print("Contains a value! It is \(number)!")
} else {
print("Doesn’t contain a number")
}
यह क्या करता है पहले जांचें कि वैकल्पिक में एक मूल्य है। यदि यह करता है , तो 'अलिखित' मान एक नए चर ( number
) को सौंपा गया है - जिसे आप तब स्वतंत्र रूप से उपयोग कर सकते हैं जैसे कि यह गैर-वैकल्पिक था। यदि वैकल्पिक में कोई मान नहीं है, तो अन्य क्लॉज़ को लागू किया जाएगा, जैसा कि आप उम्मीद करेंगे।
वैकल्पिक बंधन के बारे में क्या साफ है, क्या आप एक ही समय में कई वैकल्पिकों को खोल सकते हैं। आप केवल अल्पविराम से बयानों को अलग कर सकते हैं। यदि सभी वैकल्पिकों को हटा दिया गया था, तो बयान सफल होगा।
var anOptionalInt : Int?
var anOptionalString : String?
if let number = anOptionalInt, let text = anOptionalString {
print("anOptionalInt contains a value: \(number). And so does anOptionalString, it’s: \(text)")
} else {
print("One or more of the optionals don’t contain a value")
}
एक और साफ चाल यह है कि आप कॉमा का उपयोग मूल्य पर एक निश्चित स्थिति की जांच के लिए भी कर सकते हैं, इसे बाहर निकालने के बाद।
if let number = anOptionalInt, number > 0 {
print("anOptionalInt contains a value: \(number), and it’s greater than zero!")
}
एक इफ स्टेटमेंट के भीतर वैकल्पिक बाइंडिंग का उपयोग करने के साथ एकमात्र कैच यह है कि आप केवल स्टेटमेंट के दायरे में मौजूद अलिखित मान को एक्सेस कर सकते हैं। यदि आपको बयान के दायरे के बाहर से मूल्य तक पहुंच की आवश्यकता है, तो आप एक गार्ड स्टेटमेंट का उपयोग कर सकते हैं ।
एक गार्ड स्टेटमेंट आपको सफलता के लिए एक शर्त को परिभाषित करने की अनुमति देता है - और वर्तमान स्कोप केवल उस स्थिति को पूरा करने के लिए निष्पादित करना जारी रखेगा। उन्हें वाक्य रचना के साथ परिभाषित किया गया है guard condition else {...}
।
इसलिए, वैकल्पिक बंधन के साथ उनका उपयोग करने के लिए, आप ऐसा कर सकते हैं:
guard let number = anOptionalInt else {
return
}
(ध्यान दें कि गार्ड बॉडी के भीतर, आपको वर्तमान में निष्पादित कोड के दायरे से बाहर निकलने के लिए कंट्रोल ट्रांसफर स्टेटमेंट्स में से एक का उपयोग करना होगा )।
यदि anOptionalInt
कोई मान समाहित करता है, तो उसे अलिखित और नए number
स्थिरांक को सौंपा जाएगा । गार्ड के बाद का कोड तब निष्पादित करना जारी रखेगा। यदि इसमें कोई मान नहीं है - गार्ड कोष्ठक के भीतर कोड को निष्पादित करेगा, जिससे नियंत्रण स्थानांतरित हो जाएगा, ताकि उसके तुरंत बाद कोड निष्पादित नहीं होगा।
गार्ड स्टेटमेंट के बारे में असली साफ बात यह है कि कोड में उपयोग करने के लिए अलिखित मान अब उपलब्ध है जो स्टेटमेंट का अनुसरण करता है (जैसा कि हम जानते हैं कि भविष्य का कोड केवल तभी निष्पादित हो सकता है जब वैकल्पिक का मान हो)। बयानों के अनुसार, कई घोंसले के शिकार द्वारा बनाए गए 'कयामत के पिरामिड' को खत्म करने के लिए यह बहुत अच्छा है ।
उदाहरण के लिए:
guard let number = anOptionalInt else {
return
}
print("anOptionalInt contains a value, and it’s: \(number)!")
गार्ड भी उसी साफ-सुथरी चाल का समर्थन करते हैं जो कि यदि कथन का समर्थन करता है, जैसे कि एक ही समय में कई वैकल्पिकों को खोलना और where
क्लॉज का उपयोग करना ।
चाहे आप एक if या guard स्टेटमेंट का पूरी तरह से उपयोग करते हैं या नहीं यह इस बात पर निर्भर करता है कि भविष्य में किसी कोड में किसी मान को रखने के लिए वैकल्पिक की आवश्यकता है या नहीं ।
निल कोलेसिंग ऑपरेटर
शून्य वालों ऑपरेटर के एक गंधा आशुलिपि संस्करण है त्रिगुट सशर्त ऑपरेटर , मुख्य रूप से गैर optionals को optionals कन्वर्ट करने के लिए बनाया गया है। इसका सिंटैक्स है a ?? b
, जहां a
एक वैकल्पिक प्रकार है और b
यह उसी प्रकार है a
(हालांकि आमतौर पर गैर-वैकल्पिक)।
यह अनिवार्य रूप से आपको यह कहने देता है कि “यदि a
कोई मूल्य समाहित है, तो उसे रद्द करें। यदि इसके बाद वापस नहीं b
जाता है ”। उदाहरण के लिए, आप इसे इस तरह उपयोग कर सकते हैं:
let number = anOptionalInt ?? 0
यह एक number
निरंतर Int
प्रकार को परिभाषित करेगा , जिसमें या तो मान होगा anOptionalInt
, यदि इसमें कोई मान है, या 0
अन्यथा।
इसके लिए बस आशुलिपि है:
let number = anOptionalInt != nil ? anOptionalInt! : 0
वैकल्पिक चेनिंग
आप वैकल्पिक कॉलिंग का उपयोग कर सकते हैं ताकि किसी विधि पर कॉल किया जा सके या किसी वैकल्पिक पर संपत्ति का उपयोग किया जा सके। यह बस इसका ?
उपयोग करते समय चर नाम के साथ प्रत्यय लगाकर किया जाता है।
उदाहरण के लिए, कहें कि हमारे पास एक चर है foo
, एक वैकल्पिक Foo
उदाहरण।
var foo : Foo?
अगर हम foo
उस तरीके को कॉल करना चाहते हैं जो कुछ भी वापस नहीं करता है, तो हम बस कर सकते हैं:
foo?.doSomethingInteresting()
यदि foo
कोई मान है, तो इस पद्धति को उस पर कॉल किया जाएगा। यदि ऐसा नहीं होता है, तो कुछ भी बुरा नहीं होगा - कोड बस निष्पादित करना जारी रखेगा।
(यह nil
उद्देश्य-सी में संदेश भेजने के लिए समान व्यवहार है)
इसलिए यह गुणों के साथ-साथ कॉल विधियों को सेट करने के लिए भी उपयोग किया जा सकता है। उदाहरण के लिए:
foo?.bar = Bar()
फिर, यहाँ कुछ भी बुरा नहीं होगा अगर foo
है nil
। आपका कोड बस क्रियान्वित होता रहेगा।
एक और साफ-सुथरी ट्रिक जो आपको वैकल्पिक चैनिंग की सुविधा देती है, यह जाँचती है कि प्रॉपर्टी सेट करना या मेथड कॉल करना सफल था। आप रिटर्न मान की तुलना करके ऐसा कर सकते हैं nil
।
(ऐसा इसलिए है क्योंकि एक वैकल्पिक मूल्य एक विधि के Void?
बजाय वापस आ जाएगा Void
जो कुछ भी वापस नहीं करता है)
उदाहरण के लिए:
if (foo?.bar = Bar()) != nil {
print("bar was set successfully")
} else {
print("bar wasn’t set successfully")
}
हालांकि, जब संपत्तियों या कॉल के तरीकों का उपयोग करने की कोशिश की जाती है तो चीजें थोड़ी अधिक मुश्किल हो जाती हैं। क्योंकि foo
वैकल्पिक है, इससे लौटी कोई भी चीज़ वैकल्पिक होगी। इससे निपटने के लिए, आप या तो उन वैकल्पिक तरीकों को खोल सकते हैं जो उपरोक्त विधियों में से किसी एक का उपयोग करके वापस आते हैं - या foo
मानों को वापस करने के तरीकों या कॉलिंग विधियों तक पहुँचने से पहले खुद को अनचेक करें ।
इसके अलावा, जैसा कि नाम से पता चलता है, आप इन कथनों को एक साथ 'चेन' कर सकते हैं। इसका मतलब है कि अगर foo
कोई वैकल्पिक संपत्ति है baz
, जिसमें एक संपत्ति है qux
- आप निम्नलिखित लिख सकते हैं:
let optionalQux = foo?.baz?.qux
फिर से, क्योंकि foo
और baz
वैकल्पिक हैं, से लौटा मूल्य qux
हमेशा एक वैकल्पिक होगा चाहे वह qux
खुद वैकल्पिक हो।
map
तथा flatMap
वैकल्पिक के साथ अक्सर उपयोग की जाने वाली सुविधा कार्य map
और flatMap
कार्यों का उपयोग करने की क्षमता है । ये आपको वैकल्पिक वैरिएबल में गैर-वैकल्पिक ट्रांसफ़ॉर्म लागू करने की अनुमति देते हैं। यदि किसी वैकल्पिक का मान है, तो आप इसमें दिए गए परिवर्तन को लागू कर सकते हैं। यदि इसका कोई मूल्य नहीं है, तो यह बना रहेगा nil
।
उदाहरण के लिए, मान लें कि आपके पास एक वैकल्पिक स्ट्रिंग है:
let anOptionalString:String?
map
फ़ंक्शन को उस पर लागू करने से - हम stringByAppendingString
फ़ंक्शन का उपयोग करके इसे किसी अन्य स्ट्रिंग तक पहुंचाने के लिए कर सकते हैं ।
क्योंकि stringByAppendingString
गैर-वैकल्पिक स्ट्रिंग तर्क लेता है, हम अपने वैकल्पिक स्ट्रिंग को सीधे इनपुट नहीं कर सकते। हालाँकि, का उपयोग करके map
, हम उपयोग करने के stringByAppendingString
लिए अनुमति दे सकते हैं अगर anOptionalString
एक मूल्य है।
उदाहरण के लिए:
var anOptionalString:String? = "bar"
anOptionalString = anOptionalString.map {unwrappedString in
return "foo".stringByAppendingString(unwrappedString)
}
print(anOptionalString) // Optional("foobar")
हालाँकि, यदि anOptionalString
कोई मान नहीं है , तो map
वापस आ जाएगा nil
। उदाहरण के लिए:
var anOptionalString:String?
anOptionalString = anOptionalString.map {unwrappedString in
return "foo".stringByAppendingString(unwrappedString)
}
print(anOptionalString) // nil
flatMap
इसी तरह से काम करता है map
, सिवाय इसके कि आप बंद शरीर के भीतर से एक और वैकल्पिक वापस करने की अनुमति देता है। इसका मतलब है कि आप एक वैकल्पिक प्रक्रिया में इनपुट कर सकते हैं जिसके लिए एक गैर-वैकल्पिक इनपुट की आवश्यकता होती है, लेकिन एक वैकल्पिक आउटपुट का उत्पादन कर सकते हैं।
try!
स्विफ्ट की एरर हैंडलिंग सिस्टम को सुरक्षित रूप से Do-Try-Catch के साथ प्रयोग किया जा सकता है :
do {
let result = try someThrowingFunc()
} catch {
print(error)
}
यदि someThrowingFunc()
कोई त्रुटि करता है, तो त्रुटि को catch
ब्लॉक में सुरक्षित रूप से पकड़ा जाएगा ।
error
लगातार आप में देख catch
ब्लॉक हमारे द्वारा घोषित नहीं किया गया है - यह स्वचालित रूप से द्वारा उत्पन्न कर रहा है catch
।
आप खुद को घोषित कर सकते हैं error
, इसका फायदा यह है कि इसे एक उपयोगी प्रारूप में डालने में सक्षम है, उदाहरण के लिए:
do {
let result = try someThrowingFunc()
} catch let error as NSError {
print(error.debugDescription)
}
try
इस तरह का उपयोग करना फेंकने वाले कार्यों से आने वाली त्रुटियों को आज़माने, पकड़ने और संभालने का उचित तरीका है।
वहाँ भी है try?
जो त्रुटि को अवशोषित करता है:
if let result = try? someThrowingFunc() {
// cool
} else {
// handle the failure, but there's no error information available
}
लेकिन स्विफ्ट की त्रुटि से निपटने की प्रणाली भी इसके साथ "बल प्रयास" करने का एक तरीका प्रदान करती है try!
:
let result = try! someThrowingFunc()
इस पोस्ट में बताई गई अवधारणाएं यहां भी लागू होती हैं: यदि कोई त्रुटि होती है, तो एप्लिकेशन क्रैश हो जाएगा।
आपको केवल कभी-कभी उपयोग करना चाहिए try!
यदि आप यह साबित कर सकते हैं कि इसका परिणाम आपके संदर्भ में कभी भी विफल नहीं होगा - और यह बहुत दुर्लभ है।
अधिकांश समय आप पूर्ण Do-Try-Catch प्रणाली का उपयोग करेंगे - और वैकल्पिक एक, try?
दुर्लभ मामलों में जहां त्रुटि को संभालना महत्वपूर्ण नहीं है।
साधन
टीएल; डीआर जवाब
साथ बहुत कुछ अपवादों को छोड़कर , इस नियम सुनहरा है:
के उपयोग से बचें !
वैरिएबल वैकलिपक वैकल्पिक ( ?
), अव्यवस्थित रूप से अलिखित वैकल्पिक (IUO) ( !
) नहीं
दूसरे शब्दों में, बल्कि उपयोग करें:
var nameOfDaughter: String?
के बजाय:
var nameOfDaughter: String!
वैकल्पिक चर का उपयोग कर if let
या खोलनाguard let
या तो इस तरह के चर को खोलना:
if let nameOfDaughter = nameOfDaughter {
print("My daughters name is: \(nameOfDaughter)")
}
या इस तरह:
guard let nameOfDaughter = nameOfDaughter else { return }
print("My daughters name is: \(nameOfDaughter)")
यह उत्तर संक्षिप्त होने के लिए था, पूर्ण समझ के लिए स्वीकृत उत्तर पढ़ें
साधन
यह सवाल SO पर सभी समय के ऊपर आता है । यह पहली चीजों में से एक है जो नए स्विफ्ट डेवलपर्स के साथ संघर्ष करती है।
पृष्ठभूमि:
स्विफ्ट उन मूल्यों से निपटने के लिए "वैकल्पिक" की अवधारणा का उपयोग करता है जिनमें मूल्य शामिल हो सकते हैं, या नहीं। C जैसी अन्य भाषाओं में, आप यह दर्शाने के लिए एक चर में 0 का मान संग्रहीत कर सकते हैं कि इसमें कोई मान नहीं है। हालांकि, क्या होगा यदि 0 एक वैध मूल्य है? तो आप -1 का उपयोग कर सकते हैं। क्या होगा अगर -1 एक वैध मूल्य है? और इसी तरह।
स्विफ्ट ऑप्शंस आपको किसी भी प्रकार का एक वैरिएबल सेट करने देता है जिसमें या तो वैल्यू वैल्यू होती है या कोई वैल्यू नहीं होती है।
जब आप किसी चर को माध्य (प्रकार x, या कोई मान नहीं) घोषित करते हैं, तो आप उस प्रकार के बाद एक प्रश्न चिह्न लगाते हैं।
एक वैकल्पिक वास्तव में एक कंटेनर है जिसमें या तो दिए गए प्रकार का एक चर है, या कुछ भी नहीं है।
अंदर मूल्य लाने के लिए एक वैकल्पिक "अलिखित" होने की आवश्यकता है।
"!" ऑपरेटर एक "फोर्स अनप्रैप" ऑपरेटर है। यह कहता है "मुझ पर भरोसा करो। मुझे पता है कि मैं क्या कर रहा हूं। मैं गारंटी देता हूं कि जब यह कोड चलता है, तो चर में शून्य नहीं होगा।" यदि आप गलत हैं, तो आप दुर्घटनाग्रस्त हो जाते हैं।
जब तक आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं, "से बचें!" बल पूर्वक संचालक। यह शायद स्विफ्ट प्रोग्रामर की शुरुआत के लिए दुर्घटनाओं का सबसे बड़ा स्रोत है।
वैकल्पिक तरीकों से कैसे निपटें:
वैकल्पिक से निपटने के कई अन्य तरीके हैं जो सुरक्षित हैं। यहाँ कुछ (एक विस्तृत सूची नहीं है)
आप "वैकल्पिक बाइंडिंग" का उपयोग कर सकते हैं या "अगर कहने दें" यदि इस वैकल्पिक में कोई मान है, तो उस मान को एक नए, गैर-वैकल्पिक चर में सहेजें। यदि वैकल्पिक में कोई मान नहीं है, तो बयान के आधार पर इसे छोड़ें। "।
यहाँ हमारे foo
वैकल्पिक के साथ वैकल्पिक बंधन का एक उदाहरण है :
if let newFoo = foo //If let is called optional binding. {
print("foo is not nil")
} else {
print("foo is nil")
}
ध्यान दें कि जब आप वैकल्पिक बाइंडिंग का उपयोग करते हैं तो जो चर परिभाषित करते हैं, यदि मौजूद है (केवल "स्कोप में") तो स्टेटमेंट में।
वैकल्पिक रूप से, आप एक गार्ड स्टेटमेंट का उपयोग कर सकते हैं, जो चर के शून्य होने पर आपको अपने फ़ंक्शन से बाहर निकलने देता है:
func aFunc(foo: Int?) {
guard let newFoo = input else { return }
//For the rest of the function newFoo is a non-optional var
}
स्विफ्ट 2 में गार्ड स्टेटमेंट जोड़े गए थे। गार्ड आपको अपने कोड के माध्यम से "गोल्डन पाथ" को संरक्षित करने देता है, और नेस्टेड के बढ़ते-बढ़ते स्तरों से बचता है, जो कभी-कभी "यदि" वैकल्पिक बाइंडिंग "" का उपयोग करने के परिणामस्वरूप होता है।
एक निर्माण भी है जिसे "नील कोलेसिंग ऑपरेटर" कहा जाता है। यह "वैकल्पिक_वर ?? रिप्लेसमेंट_वल" का रूप लेता है। यह गैर-वैकल्पिक चर को उसी प्रकार के साथ लौटाता है जैसे वैकल्पिक में निहित डेटा। यदि वैकल्पिक में शून्य है, तो यह "??" के बाद अभिव्यक्ति का मान लौटाता है। प्रतीक।
तो आप इस तरह कोड का उपयोग कर सकते हैं:
let newFoo = foo ?? "nil" // "??" is the nil coalescing operator
print("foo = \(newFoo)")
आप कोशिश / कैच या गार्ड एरर हैंडलिंग का भी उपयोग कर सकते हैं, लेकिन आमतौर पर ऊपर दी गई अन्य तकनीकों में से एक क्लीनर है।
संपादित करें:
एक और, वैकल्पिक के साथ थोड़ा और सूक्ष्म गोत्र "अनुमानित रूप से अलिखित वैकल्पिक है। जब हम फू की घोषणा करते हैं, तो हम कर सकते हैं:
var foo: String!
उस मामले में फू अभी भी एक वैकल्पिक है, लेकिन आपको इसे संदर्भित करने के लिए इसे खोलना नहीं है। इसका मतलब यह है कि किसी भी समय आप फू को संदर्भित करने की कोशिश करते हैं, अगर यह शून्य है तो आप दुर्घटनाग्रस्त हो जाते हैं।
तो यह कोड:
var foo: String!
let upperFoo = foo.capitalizedString
फू की पूंजीकृत संपत्ति के संदर्भ में दुर्घटनाग्रस्त हो जाएगा, भले ही हम फो-अलोइंग फू न हों। प्रिंट ठीक लग रहा है, लेकिन यह नहीं है।
इस प्रकार आप वास्तव में अंतर्निहित अलिखित वैकल्पिक के साथ सावधान रहना चाहते हैं। (और शायद यहां तक कि पूरी तरह से उनसे बचें जब तक कि आपके पास वैकल्पिक की एक ठोस समझ न हो।)
नीचे पंक्ति: जब आप पहली बार स्विफ्ट सीख रहे हैं, तो "दिखाओ!" चरित्र भाषा का हिस्सा नहीं है। इससे आपको परेशानी होने की संभावना है।
चूंकि उपरोक्त उत्तर स्पष्ट रूप से बताते हैं कि कैसे वैकल्पिक रूप से सुरक्षित रूप से खेलना है। मैं यह समझाने की कोशिश करूंगा कि वैकल्पिक क्या वास्तव में तेज हैं।
वैकल्पिक चर घोषित करने का दूसरा तरीका है
var i : Optional<Int>
और वैकल्पिक प्रकार दो मामलों के साथ एक गणना के अलावा कुछ भी नहीं है
enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
.
.
.
}
इसलिए हमारे वेरिएबल 'i' को एक nil असाइन करना है। हम var i = Optional<Int>.none
किसी मान को असाइन या असाइन कर सकते हैं
, हम कुछ मान पास करेंगे
var i = Optional<Int>.some(28)
स्विफ्ट के अनुसार, 'निल' मूल्य का अभाव है। और उदाहरण के लिए, nil
हमें एक प्रोटोकॉल बनाने के लिए कहा जाता है, जिसे ExpressibleByNilLiteral
आप कहते हैं और महान माना जाता है, केवल इसके Optionals
अनुरूप ExpressibleByNilLiteral
और अन्य प्रकारों के अनुरूप होने को हतोत्साहित किया जाता है।
ExpressibleByNilLiteral
एक एकल विधि है जिसे init(nilLiteral:)
nil के साथ एक इंस्टासेस को आरंभीकृत करता है। आप आमतौर पर इस पद्धति को कॉल नहीं कर सकते हैं और स्विफ्ट डॉक्यूमेंटेशन के अनुसार इस इनिशियलाइज़र को सीधे कॉल करने के लिए हतोत्साहित किया जाता है क्योंकि कंपाइलर इसे तब भी कॉल करता है जब आप ऑप्शनल के साथ एक ऑप्शनल टाइप इनिशियलाइज़ करते हैं nil
।
यहां तक कि अपने आप को वैकल्पिक के आसपास मेरे सिर को (कोई भी इरादा नहीं) लपेटना है : डी हैप्पी स्विफ्टिंग ऑल ।
पहले, आपको पता होना चाहिए कि एक वैकल्पिक मूल्य क्या है। आप विस्तार के लिए स्विफ्ट प्रोग्रामिंग भाषा में कदम रख सकते हैं ।
दूसरा, आपको पता होना चाहिए कि वैकल्पिक मूल्य में दो स्थितियां हैं। एक पूर्ण मान है, और दूसरा शून्य मान है। इसलिए वैकल्पिक मूल्य लागू करने से पहले, आपको यह जांचना चाहिए कि यह किस राज्य का है।
आप if let ...
या guard let ... else
तो और उपयोग कर सकते हैं ।
एक अन्य तरीका, यदि आप अपने कार्यान्वयन से पहले चर राज्य की जांच नहीं करना चाहते हैं, तो आप var buildingName = buildingName ?? "buildingName"
इसके बजाय भी उपयोग कर सकते हैं ।
मुझे यह त्रुटि एक बार हुई थी जब मैं अपने आउटलेट मूल्यों को सेग विधि की तैयारी से निम्नानुसार सेट करने का प्रयास कर रहा था:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DestinationVC{
if let item = sender as? DataItem{
// This line pops up the error
destination.nameLabel.text = item.name
}
}
}
तब मुझे पता चला कि मैं डेस्टिनेशन कंट्रोलर आउटलेट्स के मूल्यों को सेट नहीं कर सकता क्योंकि कंट्रोलर को अभी तक लोड या इनिशियलाइज़ नहीं किया गया है।
इसलिए मैंने इसे इस तरह हल किया:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DestinationVC{
if let item = sender as? DataItem{
// Created this method in the destination Controller to update its outlets after it's being initialized and loaded
destination.updateView(itemData: item)
}
}
}
गंतव्य नियंत्रक:
// This variable to hold the data received to update the Label text after the VIEW DID LOAD
var name = ""
// Outlets
@IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
nameLabel.text = name
}
func updateView(itemDate: ObjectModel) {
name = itemDate.name
}
मुझे उम्मीद है कि यह उत्तर किसी को भी इस मुद्दे के साथ मदद करता है क्योंकि मुझे लगा कि उत्तर मिला वैकल्पिक की समझ के लिए महान संसाधन है और वे कैसे काम करते हैं लेकिन इस मुद्दे को सीधे संबोधित नहीं किया है।
मूल रूप से आपने उन स्थानों पर एक शून्य मान का उपयोग करने की कोशिश की जहां स्विफ्ट केवल गैर-शून्य लोगों को अनुमति देता है, संकलक को आप पर भरोसा करने के लिए कहकर कि वहां कभी शून्य मूल्य नहीं होगा, इस प्रकार आपके एप्लिकेशन को संकलन करने की अनुमति मिलती है।
इस तरह की घातक त्रुटि के लिए कई परिदृश्य हैं:
जबरन हटा दिया गया:
let user = someVariable!
यदि
someVariable
शून्य है, तो आपको एक दुर्घटना मिलेगी। एक फोर्स अनप्रैप करके आपने कंपाइलर से नील चेक जिम्मेदारी ले ली है, मूल रूप से एक मजबूर अनट्रैप करके आप कंपाइलर को गारंटी दे रहे हैं कि आपके पास वहां कभी भी वैल्यू नहीं होगी। और लगता है कि क्या होता है अगर किसी तरह एक शून्य मूल्य में समाप्त होता हैsomeVariable
?समाधान? वैकल्पिक बाइंडिंग (उर्फ इफ़-लेट) का उपयोग करें, वहाँ चर प्रसंस्करण करें:
if user = someVariable { // do your stuff }
मजबूर (नीचे) जातियां:
let myRectangle = someShape as! Rectangle
यहाँ बल द्वारा कास्टिंग आप संकलक को अब चिंता करने के लिए नहीं कहते हैं, क्योंकि आपके पास हमेशा एक
Rectangle
उदाहरण होगा। और जब तक वह धारण करता है, आपको चिंता करने की आवश्यकता नहीं है। समस्या तब शुरू होती है जब आप या आपके सहकर्मी परियोजना से गैर-आयत मानों को प्रसारित करना शुरू करते हैं।समाधान? वैकल्पिक बाइंडिंग (उर्फ इफ़-लेट) का उपयोग करें, वहाँ चर प्रसंस्करण करें:
if let myRectangle = someShape as? Rectangle { // yay, I have a rectangle }
वैकल्पिक रूप से अपरिवर्तित वैकल्पिक। मान लेते हैं कि आपके पास निम्न वर्ग की परिभाषा है:
class User { var name: String! init() { name = "(unnamed)" } func nicerName() { return "Mr/Ms " + name } }
अब, यदि कोई भी
name
इसे सेट करके संपत्ति के साथ खिलवाड़ नहीं करता हैnil
, तो यह अपेक्षा के अनुरूप काम करता है, हालांकि यदिUser
उस JSON से प्रारंभ किया जाता है जिसमेंname
कुंजी का अभाव है , तो आपको संपत्ति का उपयोग करने की कोशिश करते समय घातक त्रुटि मिलती है।समाधान? उनका उपयोग न करें :) जब तक आप 102% सुनिश्चित नहीं हो जाते हैं कि संपत्ति को हमेशा गैर-शून्य मान होगा, तब तक इसका उपयोग करने की आवश्यकता होती है। ज्यादातर मामलों में वैकल्पिक या गैर-वैकल्पिक में परिवर्तित करने से काम चल जाएगा। इसे गैर-वैकल्पिक बनाने से भी कंपाइलर आपको उस संपत्ति का मूल्य देने में चूक गए कोड रास्तों को बताकर आपकी मदद करेगा
असंबद्ध, या अभी तक जुड़े हुए नहीं, आउटलेट। यह परिदृश्य # 3 का एक विशेष मामला है। मूल रूप से आपके पास कुछ XIB- लोडेड वर्ग है जिसका आप उपयोग करना चाहते हैं।
class SignInViewController: UIViewController { @IBOutlet var emailTextField: UITextField! }
अब यदि आप XIB एडिटर से आउटलेट कनेक्ट करने से चूक गए हैं, तो जैसे ही आप आउटलेट का उपयोग करना चाहेंगे, ऐप क्रैश हो जाएगा। समाधान? सुनिश्चित करें कि सभी आउटलेट जुड़े हुए हैं। या
?
उन पर ऑपरेटर का उपयोग करेंemailTextField?.text = "[email protected]"
:। या आउटलेट को वैकल्पिक के रूप में घोषित करें, हालांकि इस मामले में कंपाइलर आपको कोड पर इसे अनचेक करने के लिए मजबूर करेगा।उद्देश्य-सी से आने वाले मान, और इसमें अशक्तता की व्याख्या नहीं है। मान लेते हैं कि हमारे पास निम्न उद्देश्य-सी श्रेणी है:
@interface MyUser: NSObject @property NSString *name; @end
अब यदि कोई अशक्तता एनोटेशन निर्दिष्ट नहीं है (या तो स्पष्ट रूप से या
NS_ASSUME_NONNULL_BEGIN
/ के माध्यम सेNS_ASSUME_NONNULL_END
), तोname
संपत्ति स्विफ्ट में आयात की जाएगीString!
(एक आईयूओ - अंतर्निहित अलिखित वैकल्पिक)। जैसे ही कुछ स्विफ्ट कोड मूल्य का उपयोग करना चाहेगा, यहname
शून्य होने पर दुर्घटनाग्रस्त हो जाएगा ।समाधान? अपने उद्देश्य-सी कोड में अशक्तता एनोटेशन जोड़ें। हालांकि, सावधानी बरतें कि ऑब्जेक्टिव-सी कंपाइलर थोडा अनुमेय है जब यह अशक्तता की ओर आता है, तो आप शून्य मानों के साथ समाप्त हो सकते हैं, भले ही आपने उन्हें स्पष्ट रूप से चिह्नित किया हो
nonnull
।
यह एक महत्वपूर्ण टिप्पणी है और इसलिए कि जब यह डिबगिंग nil
मूल्यों की बात आती है, तो अंतर्निहित अलिखित वैकल्पिक क्यों भ्रामक हो सकता है ।
निम्नलिखित कोड के बारे में सोचें: यह बिना किसी त्रुटि / चेतावनी के संकलित करता है:
c1.address.city = c3.address.city
फिर भी रनटाइम के दौरान यह निम्न त्रुटि देता है: घातक त्रुटि: एक वैकल्पिक मान को हटाते समय अप्रत्याशित रूप से शून्य पाया गया
क्या आप बता सकते हैं कि कौन सी वस्तु है nil
?
आप नहीं कर सकते!
पूरा कोड होगा:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var c1 = NormalContact()
let c3 = BadContact()
c1.address.city = c3.address.city // compiler hides the truth from you and then you sudden get a crash
}
}
struct NormalContact {
var address : Address = Address(city: "defaultCity")
}
struct BadContact {
var address : Address!
}
struct Address {
var city : String
}
लंबी कहानी का उपयोग करके var address : Address!
आप इस संभावना को छिपा रहे हैं कि एक चर nil
अन्य पाठकों से हो सकता है। और जब यह दुर्घटनाग्रस्त हो जाता है तो आप "क्या नरक है? मेरी address
वैकल्पिक नहीं है, इसलिए मैं दुर्घटनाग्रस्त हो रहा हूं?"
इसलिए इस तरह लिखना बेहतर है:
c1.address.city = c2.address!.city // ERROR: Fatal error: Unexpectedly found nil while unwrapping an Optional value
क्या अब आप मुझे बता सकते हैं कि वह कौन सी वस्तु थी nil
?
इस बार आपको कोड अधिक स्पष्ट कर दिया गया है। आप तर्कसंगत रूप से सोच सकते हैं और सोच सकते हैं कि यह वह address
पैरामीटर है जो जबरदस्ती अलिखित था।
पूरा कोड होगा:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var c1 = NormalContact()
let c2 = GoodContact()
c1.address.city = c2.address!.city
c1.address.city = c2.address?.city // not compile-able. No deceiving by the compiler
c1.address.city = c2.address.city // not compile-able. No deceiving by the compiler
if let city = c2.address?.city { // safest approach. But that's not what I'm talking about here.
c1.address.city = city
}
}
}
struct NormalContact {
var address : Address = Address(city: "defaultCity")
}
struct GoodContact {
var address : Address?
}
struct Address {
var city : String
}
त्रुटियों EXC_BAD_INSTRUCTION
और fatal error: unexpectedly found nil while implicitly unwrapping an Optional value
प्रकट होता है जब आप एक घोषित किया है @IBOutlet
, लेकिन स्टोरीबोर्ड से जुड़ा नहीं है ।
आपको यह भी सीखना चाहिए कि कैसे वैकल्पिक काम करते हैं, अन्य उत्तरों में उल्लेख किया गया है, लेकिन यह एकमात्र समय है जो ज्यादातर मुझे दिखाई देता है।
अगर आपको कलेक्शन में यह त्रुटि मिलती है तो CustomCell फ़ाइल और कस्टम xib भी बनाने का प्रयास करें।
मुख्य कोड पर ViewDidLoad () में यह कोड जोड़ें।
let nib = UINib(nibName: "CustomnibName", bundle: nil)
self.collectionView.register(nib, forCellWithReuseIdentifier: "cell")
एक टेबल व्यू कंट्रोलर से एक व्यू कंट्रोलर से एक सेगमेंट बनाते समय मुझे यह त्रुटि आई, क्योंकि मैं मुख्य स्टोरीबोर्ड में व्यू कंट्रोलर के लिए कस्टम क्लास का नाम बताना भूल गया था।
कुछ आसान है जो जाँचने योग्य है अगर बाकी सब ठीक लगे