स्विफ्ट में अपरिवर्तनीय त्रुटियों का प्रसंस्करण

प्रस्तावना


यह आलेख इस बात का उदाहरण है कि हम स्विफ्ट स्टैंडर्ड लाइब्रेरी फ़ंक्शंस में कैसे शोध कर सकते हैं, जिससे न केवल लाइब्रेरी डॉक्यूमेंटेशन बल्कि हमारे सोर्स कोड पर भी हमारे ज्ञान का निर्माण हो सके।


अपरिवर्तनीय त्रुटियां


सभी ईवेंट जिन्हें प्रोग्रामर "एरर्स" कहते हैं, उन्हें दो प्रकारों में विभाजित किया जा सकता है।


  • नेटवर्क कनेक्शन विफलता जैसे बाहरी कारकों के कारण होने वाली घटनाएं।
  • प्रोग्रामर की गलती के कारण होने वाली घटनाएं जैसे स्विच ऑपरेटर मामले तक पहुंचना जो अगम्य होना चाहिए।

पहले प्रकार की घटनाओं को एक नियमित नियंत्रण प्रवाह में संसाधित किया जाता है। उदाहरण के लिए, हम उपयोगकर्ता को संदेश दिखा कर और नेटवर्क कनेक्शन रिकवरी की प्रतीक्षा करने के लिए एक ऐप सेट करके नेटवर्क विफलता पर प्रतिक्रिया करते हैं।


हम कोड के उत्पादन में जाने से पहले दूसरे प्रकार की घटनाओं का पता लगाने और उन्हें खत्म करने का प्रयास करते हैं। एक दृष्टिकोण यहां एक डिबगेबल स्थिति में प्रोग्राम निष्पादन को समाप्त करने वाले कुछ रनटाइम चेक को चलाने और एक संदेश को प्रिंट करने के लिए है जहां कोड में त्रुटि हुई है।


उदाहरण के लिए, एक प्रोग्रामर निष्पादन को समाप्त कर सकता है यदि आवश्यक प्रारंभ करनेवाला प्रदान नहीं किया गया था लेकिन उसे बुलाया गया था। जो कि पहले टेस्ट रन के दौरान हमेशा देखा और तय किया जाएगा।


required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } 

एक अन्य उदाहरण सूचकांकों के बीच स्विच करना है (मान लें कि किसी कारण से आप गणना का उपयोग नहीं कर सकते हैं)।


 switch index { case 0: // something is done here case 1: // other thing is done here case 2: // and other thing is done here default: assertionFailure("Impossible index") } 

फिर, एक प्रोग्रामर डिबगिंग के दौरान दुर्घटना का कारण बनने जा रहा है ताकि अनिवार्य रूप से अनुक्रमण में एक बग को नोटिस किया जा सके।


स्विफ्ट स्टैंडर्ड लाइब्रेरी (स्विफ्ट 4.2 के लिए) से पांच समाप्ति कार्य हैं।


 func precondition(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) 

 func preconditionFailure(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) -> Never 

 func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) 

 func assertionFailure(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) 

 func fatalError(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) -> Never 

पांच समाप्ति कार्यों में से हमें कौन सा पसंद करना चाहिए?


स्रोत कोड बनाम प्रलेखन


स्रोत कोड देखें । हम निम्नलिखित को अभी देख सकते हैं:


  1. इन पांच कार्यों में से प्रत्येक या तो कार्यक्रम के निष्पादन को समाप्त करता है या कुछ भी नहीं करता है।
  2. संभावित समाप्ति दो तरह से होती है।
    • _assertionFailure(_:_:file:line:flags:) कॉल करके एक सुविधाजनक डिबग संदेश मुद्रित करने के साथ।
    • बिना डिबग संदेश के केवल Builtin.condfail(error._value) या Builtin.int_trap() कॉल Builtin.condfail(error._value)
  3. पांच समाप्ति कार्यों के बीच अंतर उन स्थितियों में निहित है जिनके तहत उपरोक्त सभी होता है।
  4. fatalError(_:file:line) कॉल _assertionFailure(_:_:file:line:flags:) बिना शर्त।
  5. अन्य चार समाप्ति फ़ंक्शन निम्न कॉन्फ़िगरेशन मूल्यांकन फ़ंक्शन को कॉल करके स्थितियों का मूल्यांकन करते हैं। (वे एक अंडरस्कोर के साथ शुरू करते हैं जिसका अर्थ है कि वे आंतरिक हैं और सीधे एक प्रोग्रामर द्वारा नहीं बुलाया जाना चाहिए जो स्विफ्ट लाइब्रेरी लाइब्रेरी का उपयोग करते हैं)।
    • _isReleaseAssertConfiguration()
    • _isDebugAssertConfiguration()
    • _isFastAssertConfiguration()

अब हम प्रलेखन को देखें । हम निम्नलिखित को अभी देख सकते हैं।


  1. fatalError(_:file:line) बिना किसी दिए गए संदेश को प्रिंट करता है और निष्पादन को रोक देता है
  2. अन्य चार समाप्ति कार्यों के प्रभाव का उपयोग किए गए बिल्ड फ़्लैग के आधार पर भिन्न होता है: -Onone , -O , -Ounchecked । उदाहरण के लिए, पहले से देखे जाने वाले परिणाम preconditionFailure(_:file:line:) प्रलेखन
  3. हम SWIFT_OPTIMIZATION_LEVEL कंपाइलर बिल्ड सेटिंग के माध्यम से इन बिल्ड फ्लैग को सेट कर सकते हैं।
  4. हम Xcode 10 प्रलेखन से यह भी जानते हैं कि एक और अनुकूलन ध्वज - -Osize - पेश किया गया है।
  5. इस प्रकार हमारे पास विचार करने के लिए चार अनुकूलन बिल्ड फ्लैग हैं।
    • -Onone (ऑप्टिमाइज़ न करें)
    • -O (गति के लिए अनुकूलन)
    • -Osize (आकार के लिए ऑप्टिमाइज़ करें)
    • -Ounchecked (कई संकलक जाँच बंद करें)

हम यह निष्कर्ष निकाल सकते हैं कि चार समाप्ति कार्यों में मूल्यांकन किया गया कॉन्फ़िगरेशन इन बिल्ड फ़्लैग द्वारा निर्धारित किया गया है।


रनिंग कॉन्फ़िगरेशन मूल्यांकन कार्य


यद्यपि कॉन्फ़िगरेशन मूल्यांकन फ़ंक्शन आंतरिक उपयोग के लिए डिज़ाइन किए गए हैं, उनमें से कुछ परीक्षण उद्देश्यों के लिए सार्वजनिक हैं , और हम उन्हें CLI के माध्यम से बाश में निम्नलिखित आदेश दे सकते हैं।


 $ echo 'print(_isFastAssertConfiguration())' >conf.swift $ swift conf.swift false $ swift -Onone conf.swift false $ swift -O conf.swift false $ swift -Osize conf.swift false $ swift -Ounchecked conf.swift true 

 $ echo 'print(_isDebugAssertConfiguration())' >conf.swift $ swift conf.swift true $ swift -Onone conf.swift true $ swift -O conf.swift false $ swift -Osize conf.swift false $ swift -Ounchecked conf.swift false 

इन परीक्षणों और स्रोत कोड निरीक्षण हमें निम्नलिखित किसी न किसी निष्कर्ष पर ले जाते हैं।


तीन परस्पर अनन्य कॉन्फ़िगरेशन हैं।


  • रिलीज़ कॉन्फ़िगरेशन या तो -O प्रदान करता है या एक -Osize बिल्ड ध्वज प्रदान करता है।
  • डीबग कॉन्फ़िगरेशन या तो -Onone बिल्ड फ़्लैग या कोई ऑप्टिमाइज़ेशन फ़्लैग प्रदान करके सेट किया गया है।
  • _isFastAssertConfiguration() का मूल्यांकन true करने के लिए किया जाता true अगर -Ounchecked बिल्ड ध्वज सेट किया गया है। यद्यपि इस फ़ंक्शन के नाम में एक शब्द "तेज" है, इसका स्पीड- -O बिल्ड फ्लैग के अनुकूलन के साथ कोई लेना-देना नहीं है।

एनबी: डिबग बिल्ड या रिलीज़ बिल्ड के होने पर ये निष्कर्ष सख्त परिभाषा नहीं हैं। यह अधिक जटिल मुद्दा है। लेकिन ये निष्कर्ष कार्यों के उपयोग को समाप्त करने के संदर्भ के लिए सही हैं।


चित्र को सरल बनाना


-Ounchecked


आइए देखें कि -Ounchecked ध्वज क्या है (यह यहाँ अप्रासंगिक है) लेकिन कार्य भूमिका के उपयोग के संदर्भ में इसकी भूमिका क्या है


  • precondition(_:_:file:line:) लिए दस्तावेज़ीकरण precondition(_:_:file:line:) और assert(_:_:file:line:) कहना है, "में- -Ounchecked बिल्ड, स्थिति का मूल्यांकन नहीं किया गया है, लेकिन -Ounchecked यह मान सकता है कि यह हमेशा सच का मूल्यांकन करता है)। उस धारणा को संतुष्ट करने में विफलता एक गंभीर प्रोग्रामिंग त्रुटि है। "
  • preconditionFailure(_:file:line) और assertionFailure(_:file:line:) लिए दस्तावेज़ीकरण, " -Ounchecked बनाता है, ऑप्टिमाइज़र यह मान सकता है कि इस फ़ंक्शन को कभी नहीं कहा जाता है। उस धारणा को संतुष्ट करने के लिए विफलता एक गंभीर प्रोग्रामिंग त्रुटि है। "
  • हम स्रोत कोड से देख सकते हैं कि _isFastAssertConfiguration() का true मूल्यांकन नहीं होना चाहिए । (अगर ऐसा होता है, तो अजीब _conditionallyUnreachable() कहा जाता है। देखें लाइनें 136 और _conditionallyUnreachable() )

अधिक सीधे बोलते हुए, आपको अपने प्रोग्राम के लिए -Ounchecked बिल्ड फ़्लैग सेट के साथ निम्नलिखित चार समाप्ति कार्यों की -Ounchecked की अनुमति नहीं देनी चाहिए


  • precondition(_:_:file:line:)
  • preconditionFailure(_:file:line)
  • assert(_:_:file:line:)
  • assertionFailure(_:file:line:)

आवेदन करते समय केवल fatalError(_:file:line) उपयोग करें और एक ही समय में अनुमति देते हुए कि fatalError(_:file:line) निर्देश के साथ आपके प्रोग्राम का बिंदु fatalError(_:file:line) पहुंच सकता है।


एक शर्त जाँच की भूमिका


समापन कार्यों में से दो हमें शर्तों के लिए जाँच करते हैं। स्रोत कोड निरीक्षण हमें यह देखने की अनुमति देता है कि यदि स्थिति विफल है, तो कार्य व्यवहार उसके संबंधित चचेरे भाई के व्यवहार के समान है:


  • precondition(_:_:file:line:) preconditionFailure(_:file:line) बन जाती है। preconditionFailure(_:file:line) ,
  • assert(_:_:file:line:) assertionFailure(_:file:line:) हो जाता है। assertionFailure(_:file:line:)

वह ज्ञान आगे के विश्लेषण को आसान बनाता है।


रिलीज़ बनाम डिबग कॉन्फ़िगरेशन


आखिरकार, आगे के प्रलेखन और स्रोत कोड निरीक्षण हमें निम्नलिखित तालिका तैयार करने की अनुमति देते हैं।


कार्य समाप्त करना


यह अब स्पष्ट है कि एक प्रोग्रामर के लिए सबसे महत्वपूर्ण विकल्प यह है कि प्रोग्राम व्यवहार कैसा होना चाहिए, अगर रनटाइम चेक में कोई त्रुटि सामने आती है।


यहां मुख्य कुंजी यह है कि assert(_:_:file:line:) और assertionFailure(_:file:line:) कार्यक्रम की विफलता के प्रभाव को कम गंभीर बनाते हैं। उदाहरण के लिए, एक iOS ऐप ने UI को दूषित कर दिया है (क्योंकि कुछ महत्वपूर्ण रनटाइम चेक विफल हो गए थे) लेकिन यह क्रैश नहीं होगा।


लेकिन वह परिदृश्य वह नहीं हो सकता है जैसा आप चाहते थे। आपके पास एक विकल्प है।


Never टाइप Never करें


Never भी एक वापसी प्रकार के फ़ंक्शन के रूप में उपयोग Never किया जाता है जो बिना किसी त्रुटि, जाल, या अन्यथा सामान्य रूप से समाप्त नहीं करता है। उन प्रकार के फ़ंक्शन वास्तव में वापस नहीं आते हैं, वे कभी नहीं लौटते हैं।


पांच समाप्ति कार्यों के बीच, केवल preconditionFailure(_:file:line) और fatalError(_:file:line) Never वापस Never आती क्योंकि केवल ये दो कार्य बिना शर्त के प्रोग्राम निष्पादन को रोकते हैं और इसलिए कभी वापस नहीं आते हैं।


कमांड लाइन ऐप में Never टाइप का उपयोग करने का एक अच्छा उदाहरण यहां दिया गया है। (हालांकि यह उदाहरण स्विफ्ट स्टैंडर्ड लाइब्रेरी टर्मिनेटिंग फ़ंक्शंस का उपयोग नहीं करता है लेकिन इसके बजाय मानक सी exit() फ़ंक्शन)।


 func printUsagePromptAndExit() -> Never { print("Usage: command directory") exit(1) } guard CommandLine.argc == 2 else { printUsagePromptAndExit() } // ... 

यदि printUsagePromptAndExit() Never बजाय Void देता है, तो आपको संदेश के साथ एक बिल्डटाइम त्रुटि मिलती है, " 'गार्ड' बॉडी के माध्यम से गिरना नहीं चाहिए, गुंजाइश से बाहर निकलने के लिए 'वापसी' या 'थ्रो' का उपयोग करने पर विचार करें "। Never का उपयोग करके आप पहले से कह रहे हैं कि आप कभी भी दायरे से बाहर नहीं निकलेंगे और इसलिए संकलक आपको बिल्डटाइम त्रुटि नहीं देगा। अन्यथा, आपको गार्ड कोड ब्लॉक के अंत में return जोड़ना चाहिए, जो अच्छा नहीं लगता है।


टेकअवे


  • इससे कोई फ़र्क नहीं पड़ता कि कौन सी समाप्ति समारोह का उपयोग करें यदि आप सुनिश्चित हैं कि आपके सभी रनटाइम चेक केवल डिबग कॉन्फ़िगरेशन के लिए प्रासंगिक हैं।
  • आवेदन करते समय केवल fatalError(_:file:line) उपयोग करें और एक ही समय में अनुमति देते हुए कि fatalError(_:file:line) अनुदेश के साथ अपने कार्यक्रम के बिंदु fatalError(_:file:line) पहुंच सकते हैं।
  • assert(_:_:file:line:) उपयोग करें assert(_:_:file:line:) और assertionFailure(_:file:line:) । कम से कम आपका ऐप क्रैश नहीं होगा।
  • अपने कोड को साफ-सुथरा बनाने के लिए Never उपयोग Never करें।


Source: https://habr.com/ru/post/hi440884/


All Articles