स्विफ्ट 2: कॉल फेंक सकते हैं, लेकिन यह 'कोशिश' के साथ चिह्नित नहीं है और त्रुटि को नियंत्रित नहीं किया जाता है


161

जब मैंने Xcode 7 बीटा स्थापित किया और स्विफ्ट कोड को स्विफ्ट 2 में परिवर्तित किया, तो मुझे कोड के साथ कुछ समस्या मिली जिसे मैं समझ नहीं सकता। मुझे पता है कि स्विफ्ट 2 नया है, इसलिए मैं खोज करता हूं और यह पता लगाता हूं कि इसके बारे में कुछ नहीं है, मुझे एक प्रश्न लिखना चाहिए।

यहाँ त्रुटि है:

कॉल फेंक सकते हैं, लेकिन यह 'कोशिश' के साथ चिह्नित नहीं है और त्रुटि को नियंत्रित नहीं किया गया है

कोड:

func deleteAccountDetail(){
        let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
        let request = NSFetchRequest()
        request.entity = entityDescription

        //The Line Below is where i expect the error
        let fetchedEntities = self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
        }

        do {
            try self.Context!.save()
        } catch _ {
        }

    }

स्नैपशॉट: यहां छवि विवरण दर्ज करें

जवाबों:


168

आपको उस त्रुटि को पकड़ना होगा जैसे आप पहले से ही अपने save()कॉल के लिए कर रहे हैं और चूंकि आप यहां कई त्रुटियां संभाल रहे हैं, इसलिए आप tryकई कॉल को क्रमिक रूप से एक सिंगल-कैच ब्लॉक में कर सकते हैं, जैसे:

func deleteAccountDetail() {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()
    request.entity = entityDescription

    do {
        let fetchedEntities = try self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
            self.Context!.deleteObject(entity)
        }

        try self.Context!.save()
    } catch {
        print(error)
    }
}

या जैसा कि @ bames53 ने नीचे टिप्पणी में बताया है, अक्सर यह बेहतर अभ्यास होता है कि त्रुटि को पकड़ने के लिए नहीं जहां इसे फेंक दिया गया था। आप विधि को throwsतब tryतक चिह्नित कर सकते हैं जब तक विधि को कॉल करने के लिए। उदाहरण के लिए:

func deleteAccountDetail() throws {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()

    request.entity = entityDescription

    let fetchedEntities = try Context.executeFetchRequest(request) as! [AccountDetail]

    for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
    }

    try self.Context!.save()
}

इससे मुझे यह पता लगाने में मदद मिली, धन्यवाद।
फरहाद

5
वास्तव में यह आवश्यक नहीं है कि अपवाद यहां पकड़ा जाए। केवल tryफ़ंक्शन कॉल में कीवर्ड जोड़ना संभव है , और इस फ़ंक्शन को घोषित करना func deleteAccountDetail() throw। या यदि आपने गारंटी दी है कि फ़ंक्शन दिए गए इनपुट के लिए नहीं फेंकेंगे, तो आप उपयोग कर सकते हैं try!
bames53

4
मैं इसे नाइटिक तक नहीं लाता हूं, लेकिन क्योंकि यह वास्तव में बहुत महत्वपूर्ण अपवाद आधारित त्रुटि से निपटने के लिए महत्वपूर्ण है, ज्यादातर अपवाद जहां अपवाद होते हैं, वे अपवादों को नहीं पकड़ते हैं। तीन प्रकार के स्थान हैं जहां अपवादों को पकड़ना उचित है। अन्य सभी स्थानों में, कोड को अपवादों को स्पष्ट रूप से नहीं संभालना चाहिए, और deinit()सफाई करने के लिए अंतर्निहित कॉल पर भरोसा करना चाहिए (यानी, RAII), या कभी-कभी deferकुछ तदर्थ सफाई करने के लिए उपयोग करना चाहिए। अपवादों के लिए अपवादों को देखें। (यह C ++ के बारे में बात करता है, लेकिन मूल सिद्धांत स्विफ्ट अपवादों पर भी लागू होते हैं।)
bames53

लेकिन आप फ़ंक्शन कैसे चलाएंगे? अगर मैं @ bames53 रास्ते से जाऊँ?
फरहाद

1
@NickMoore स्विफ्ट डेवलपर्स उन्हें कॉल करने के लिए क्या चुनते हैं, इससे कोई फर्क नहीं पड़ता कि वे वास्तव में क्या हैं। स्विफ्ट की नई त्रुटि से निपटने प्रणाली अपवादों का कार्यान्वयन है क्योंकि इस शब्द का उपयोग आमतौर पर उद्योग के बाकी हिस्सों में किया जाता है।
bames53

41

जब किसी फ़ंक्शन throwsको स्विफ्ट के साथ घोषित किया जाता है, तो आपको फ़ंक्शन कॉल साइट को एनोटेट करना चाहिए tryया उसके साथ try!। उदाहरण के लिए, एक फेंकने का कार्य दिया गया:

func willOnlyThrowIfTrue(value: Bool) throws {
  if value { throw someError }
}

इस समारोह को इस तरह कहा जा सकता है:

func foo(value: Bool) throws {
  try willOnlyThrowIfTrue(value)
}

यहां हम कॉल को एनोटेट करते हैं try, जो पाठक को कहता है कि यह फ़ंक्शन अपवाद फेंक सकता है, और कोड के किसी भी निम्नलिखित लाइनों को निष्पादित नहीं किया जा सकता है। हमें इस फ़ंक्शन को भी एनोटेट करना होगा throws, क्योंकि यह फ़ंक्शन एक अपवाद फेंक सकता है (यानी, जब willOnlyThrowIfTrue()फेंकता है, तो fooस्वचालित रूप से अपवाद को ऊपर की ओर फिर से फेंक देगा।

यदि आप एक फ़ंक्शन को कॉल करना चाहते हैं जिसे संभवतः फेंकने के रूप में घोषित किया गया है, लेकिन जिसे आप जानते हैं वह आपके मामले में नहीं फेंकेंगे क्योंकि आप इसे सही इनपुट दे रहे हैं, तो आप उपयोग कर सकते हैं try!

func bar() {
  try! willOnlyThrowIfTrue(false)
}

इस तरह, जब आप गारंटी देते हैं कि कोड नहीं फेंकेगा, तो आपको अपवाद प्रचार को अक्षम करने के लिए अतिरिक्त बॉयलरप्लेट कोड में नहीं डालना होगा।

try!रनटाइम पर लागू किया जाता है: यदि आप उपयोग करते हैं try!और फ़ंक्शन समाप्त हो जाता है, तो रनटाइम त्रुटि के साथ आपके प्रोग्राम का निष्पादन समाप्त हो जाएगा।

अधिकांश अपवाद हैंडलिंग कोड को ऊपर की तरह दिखना चाहिए: या तो आप अपवादों को ऊपर की ओर प्रचारित करते हैं, जब वे होते हैं, या आप ऐसी स्थिति सेट करते हैं, अन्यथा संभव अपवादों को खारिज कर दिया जाता है। आपके कोड में मौजूद अन्य संसाधनों की सफाई वस्तु विनाश (यानी deinit()), या कभी-कभी deferएड कोड के माध्यम से होनी चाहिए ।

func baz(value: Bool) throws {

  var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
  var data = NSData(contentsOfFile:filePath)

  try willOnlyThrowIfTrue(value)

  // data and filePath automatically cleaned up, even when an exception occurs.
}

यदि किसी भी कारण से आपके पास क्लीन अप कोड है जिसे चलाने की आवश्यकता है लेकिन deinit()फ़ंक्शन में नहीं है , तो आप उपयोग कर सकते हैं defer

func qux(value: Bool) throws {
  defer {
    print("this code runs when the function exits, even when it exits by an exception")
  }

  try willOnlyThrowIfTrue(value)
}

अधिकांश कोड जो अपवादों से संबंधित हैं, उन्हें कॉल करने वालों के लिए ऊपर की ओर प्रचारित किया जाता है, रास्ते से सफाई कर रहा है deinit()या defer। ऐसा इसलिए है क्योंकि अधिकांश कोड को पता नहीं है कि त्रुटियों का क्या करना है; यह पता है कि क्या गलत हुआ, लेकिन इसमें इस बारे में पर्याप्त जानकारी नहीं है कि कुछ उच्च स्तरीय कोड क्या करने की कोशिश कर रहे हैं ताकि यह पता चल सके कि त्रुटि के बारे में क्या करना है। यह नहीं पता कि उपयोगकर्ता के लिए एक संवाद प्रस्तुत करना उचित है, या यदि उसे पुनः प्रयास करना चाहिए, या यदि कुछ और उपयुक्त है।

उच्च स्तरीय कोड, हालांकि, किसी भी त्रुटि की स्थिति में वास्तव में क्या करना चाहिए, यह जानना चाहिए। इसलिए अपवाद विशिष्ट त्रुटियों को बुलबुले बनाने की अनुमति देते हैं जहां से वे शुरू में वहां होते हैं जहां उन्हें संभाला जा सकता है।

अपवादों को संभालना catchबयानों के माध्यम से किया जाता है ।

func quux(value: Bool) {
  do {
    try willOnlyThrowIfTrue(value)
  } catch {
    // handle error
  }
}

आपके पास कई कैच स्टेटमेंट हो सकते हैं, प्रत्येक एक अलग तरह के अपवाद को पकड़ सकता है।

  do {
    try someFunctionThatThowsDifferentExceptions()
  } catch MyErrorType.errorA {
    // handle errorA
  } catch MyErrorType.errorB {
    // handle errorB
  } catch {
    // handle other errors
  }

अपवादों के साथ सर्वोत्तम प्रथाओं के बारे में अधिक जानकारी के लिए, http://exceptionafecode.com/ देखें । यह विशेष रूप से C ++ पर लक्षित है, लेकिन स्विफ्ट अपवाद मॉडल की जांच करने के बाद, मेरा मानना ​​है कि मूल स्विफ्ट पर भी लागू होता है।

स्विफ्ट सिंटैक्स और एरर हैंडलिंग मॉडल के विवरण के लिए, द स्विफ्ट प्रोग्रामिंग लैंग्वेज (स्विफ्ट 2 प्रीलेयरेज़) पुस्तक देखें ।


मूल रूप से पकड़ ही त्रुटि को संभाल सकता है? या इनपुट समारोह
फरहद

1
@BrianS मुझे यकीन नहीं है कि आप क्या पूछ रहे हैं, विशेष रूप से एक 'इनपुट फ़ंक्शन' के संबंध में, लेकिन 'पकड़' अनिवार्य रूप से अपवादों के संदर्भ में 'हैंडल' का एक पर्याय है। यह कहना है, एक अपवाद को पकड़ना और एक अपवाद को संभालना एक ही बात है, जहां तक ​​प्रोग्रामिंग भाषाओं का संबंध है।
bames53

मेरे पास एक त्रुटि है जो मुझे समझ नहीं आ रही है, क्या आप कृपया मेरी मदद कर सकते हैं? Invalid conversion from throwing function of type '() throws -> _' to non-throwing function type '(NSData?, NSURLResponse?, NSError?) -> Void'
फरहाद

@BrianS ऐसा लगता है कि आप कहीं गलत हस्ताक्षर वाले फ़ंक्शन का उपयोग कर रहे हैं। कुछ को एक फ़ंक्शन दिए जाने की उम्मीद है जो NSData?, NSURLResponse?, NSError?तर्क के रूप में लेता है, लेकिन आप इसे एक ऐसा फ़ंक्शन दे रहे हैं जो कोई तर्क नहीं लेता है।
bames53

या कुछ अपेक्षा करता है कि एक फ़ंक्शन अपवादों को घोषित नहीं करता है और आप इसे एक ऐसा फ़ंक्शन दे रहे हैं जो अपवादों को फेंकता है।
bames53
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.