स्विफ्ट-भाषा में त्रुटि-हैंडलिंग


190

मैंने स्विफ्ट में बहुत अधिक नहीं पढ़ा है, लेकिन एक बात जो मैंने देखी है कि कोई अपवाद नहीं है। तो वे स्विफ्ट में त्रुटि से निपटने के लिए कैसे करते हैं? क्या किसी को त्रुटि से संबंधित कुछ भी मिला है?


1
मुझे
ओब्ज

13
@ अच्छा पुराने segfault तरीका है?
पाको

स्विफ्ट में एक NSTimer बनाया और जब मैंने फ़ंक्शन को गलत किया तो यह दुर्घटनाग्रस्त हो गया और मुझे यह कहते हुए एक त्रुटि दी कि यह विधि नहीं मिल
पाई

3
आप इस लेख में दिए गए निर्देशों का पालन करते हुए स्विफ्ट के लिए ट्राइ-कैच समर्थन जोड़ सकते हैं: मध्यम.com
विलियम फाल्कन

@peko आप स्विफ्ट में सेगफॉल्ट को कैसे हैंडल करते हैं? मुझे नहीं लगता कि यह अब तक संभव है, जो दुखद रूप से कुछ त्रुटियों को अप्राप्य बनाता है
ऑरलिन जॉर्जीव

जवाबों:


148

स्विफ्ट 2 और 3

स्विफ्ट 2 में चीजें थोड़ी बदल गई हैं, क्योंकि एक नया त्रुटि-हैंडलिंग तंत्र है, यह कुछ हद तक अपवादों के समान है लेकिन विस्तार से अलग है।

1. त्रुटि की संभावना का संकेत

यदि फ़ंक्शन / विधि यह इंगित करना चाहती है कि यह एक त्रुटि फेंक सकता है, तो इसमें throwsइस तरह कीवर्ड होना चाहिए

func summonDefaultDragon() throws -> Dragon

नोट: फ़ंक्शन वास्तव में फेंक सकता है इस प्रकार की त्रुटि के लिए कोई विनिर्देश नहीं है। यह घोषणा केवल यह बताती है कि फ़ंक्शन किसी भी प्रकार के त्रुटिटाइप को लागू करने का एक उदाहरण फेंक सकता है या बिल्कुल भी नहीं फेंक रहा है।

2. त्रुटियों को फेंकने वाले फ़ंक्शन को लागू करना

फ़ंक्शन को इनवॉइस करने के लिए, आपको इस तरह का प्रयास करना होगा

try summonDefaultDragon()

इस लाइन को आम तौर पर इस तरह के कैच-ब्लॉक को पेश करना चाहिए

do {
    let dragon = try summonDefaultDragon() 
} catch DragonError.dragonIsMissing {
    // Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
    // Other specific-case error-handlng
} catch {
    // Catch all error-handling
}

नोट: पकड़ खंड स्विफ्ट पैटर्न के सभी शक्तिशाली विशेषताओं का उपयोग करते हुए मिलान करते हैं ताकि आप यहां बहुत लचीले हों।

आप त्रुटि को प्रचारित करने का निर्णय ले सकते हैं, यदि आप एक ऐसे फ़ंक्शन से एक फेंकने वाले फ़ंक्शन को बुला रहे हैं जो स्वयं throwsकीवर्ड के साथ चिह्नित है :

func fulfill(quest: Quest) throws {
    let dragon = try summonDefaultDragon()
    quest.ride(dragon)
} 

वैकल्पिक रूप से, आप फेक फंक्शन का उपयोग करके कॉल कर सकते हैं try?:

let dragonOrNil = try? summonDefaultDragon()

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

जिसका अर्थ है कि आप try?उपयोगी कथनों के साथ भी संयोजन कर सकते हैं जैसे:

if let dragon = try? summonDefaultDragon()

या

guard let dragon = try? summonDefaultDragon() else { ... }

अंत में, आप यह तय कर सकते हैं कि आप जानते हैं कि त्रुटि वास्तव में नहीं होगी (उदाहरण के लिए क्योंकि आपने पहले से जाँच की है और आवश्यक शर्तें हैं) और try!कीवर्ड का उपयोग करें :

let dragon = try! summonDefaultDragon()

यदि फ़ंक्शन वास्तव में एक त्रुटि फेंकता है, तो आपको अपने आवेदन में एक रनटाइम त्रुटि मिलेगी और एप्लिकेशन समाप्त हो जाएगा।

3. त्रुटि फेंकना

त्रुटि फेंकने के लिए आप इस तरह से कीवर्ड का उपयोग करें

throw DragonError.dragonIsMissing

आप ErrorTypeप्रोटोकॉल के अनुरूप कुछ भी फेंक सकते हैं । शुरुआत के NSErrorलिए इस प्रोटोकॉल के अनुरूप है, लेकिन आप शायद एनम-आधारित के साथ जाना चाहते हैं ErrorTypeजो आपको कई संबंधित त्रुटियों को समूह करने में सक्षम बनाता है, संभवतः डेटा के अतिरिक्त टुकड़ों के साथ, जैसे कि

enum DragonError: ErrorType {
    case dragonIsMissing
    case notEnoughMana(requiredMana: Int)
    ...
}

नई स्विफ्ट 2 और 3 त्रुटि तंत्र और जावा / सी # / सी + + शैली अपवादों के बीच मुख्य अंतर निम्नानुसार हैं:

  • सिंटैक्स थोड़ा अलग है: do-catch+ try+ deferबनाम पारंपरिक try-catch-finallyसिंटैक्स।
  • अपवाद हैंडलिंग आमतौर पर सफलता पथ की तुलना में अपवाद पथ में बहुत अधिक निष्पादन समय लगाती है। स्विफ्ट 2.0 त्रुटियों के साथ ऐसा नहीं है, जहां सफलता पथ और त्रुटि पथ की लागत लगभग समान है।
  • सभी त्रुटि फेंक कोड घोषित किए जाने चाहिए, जबकि अपवाद कहीं से भी फेंके गए हो सकते हैं। सभी त्रुटि जावा नामकरण में "जाँच अपवाद" हैं। हालांकि, जावा के विपरीत, आप संभावित रूप से फेंकी गई त्रुटियों को निर्दिष्ट नहीं करते हैं।
  • स्विफ्ट अपवाद ObjC अपवादों के साथ संगत नहीं हैं। आपका do-catchब्लॉक किसी भी NSException को नहीं पकड़ेगा, और इसके विपरीत, इसके लिए आपको ObjC का उपयोग करना होगा।
  • स्विफ्ट अपवाद कोको NSErrorविधि की परंपराओं के साथ संगत हैं false( या Boolवापस लौटने वाले कार्यों के लिए) या nil( AnyObjectलौटने वाले कार्यों के लिए) और NSErrorPointerत्रुटि विवरण के साथ गुजर रहे हैं।

त्रुटि को कम करने के लिए एक अतिरिक्त सिंटैटिक-चीनी के रूप में, दो और अवधारणाएं हैं

  • आस्थगित क्रियाएँ ( deferकीवर्ड का उपयोग करके ) जो आपको जावा / सी # / आदि में अंत में ब्लॉक के समान प्रभाव प्राप्त करने देती हैं
  • गार्ड स्टेटमेंट ( guardकीवर्ड का उपयोग करते हुए ) जो आपको सामान्य त्रुटि की जाँच / सिग्नलिंग कोड की तुलना में कम / यदि कोड लिखते हैं।

स्विफ्ट 1

रनटाइम त्रुटियाँ:

जैसा कि लिएंड्रो रनटाइम त्रुटियों से निपटने के लिए सुझाव देते हैं (जैसे नेटवर्क कनेक्टिविटी की समस्याएं, डेटा पार्स करना, फ़ाइल खोलना, आदि) आपको NSErrorओब्जेक में जैसे आप का उपयोग करना चाहिए , क्योंकि फाउंडेशन, ऐपिट, यूआईकिट, आदि ने इस तरह से अपनी त्रुटियों की रिपोर्ट की है। तो यह भाषा की चीज से ज्यादा ढांचा है।

एक और लगातार पैटर्न जो प्रयोग किया जा रहा है, वो है AFNetworking की तरह विभाजक सफलता / विफलता ब्लॉक:

var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
    success: { (NSURLSessionDataTask) -> Void in
        println("Success")
    },
    failure:{ (NSURLSessionDataTask, NSError) -> Void in
        println("Failure")
    })

अभी भी विफलता ब्लॉक को अक्सर NSErrorउदाहरण मिलता है, त्रुटि का वर्णन करता है।

प्रोग्रामर त्रुटियाँ:

प्रोग्रामर त्रुटियों के लिए (जैसे सरणी तत्व की सीमा तक पहुंच से बाहर, एक फ़ंक्शन कॉल के लिए पारित अवैध तर्क, आदि) आपने ओबजैक में अपवादों का उपयोग किया। स्विफ्ट भाषा को अपवादों (जैसे throw, catchकीवर्ड आदि) के लिए कोई भाषा समर्थन नहीं लगता है । हालाँकि, जैसा कि प्रलेखन से पता चलता है कि यह ओबीजीसी के समान रनटाइम पर चल रहा है, और इसलिए आप अभी भी NSExceptionsइस तरह फेंकने में सक्षम हैं :

NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()

आप बस उन्हें शुद्ध स्विफ्ट में नहीं पकड़ सकते हैं, हालांकि आप ओबीजीसी कोड में अपवादों को पकड़ने का विकल्प चुन सकते हैं।

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


20
कोको एपीआई (NSFileHandle) का उपयोग करके "नेटवर्क कनेक्टिविटी समस्याएं" और "फाइलें खोलना" उन अपवादों को फेंक सकता है जिन्हें पकड़ने की आवश्यकता है। स्विफ्ट में अपवाद के बिना, आपको अपने प्रोग्राम के इस हिस्से को ऑब्जेक्टिव-सी में लागू करने की जरूरत है या बीएसडी सी एपीआई (जो दोनों ही खराब वर्क-अराउंड हैं) का उपयोग करके अपने सभी काम करते हैं। अधिक के लिए NSFileHandle.writeData के लिए दस्तावेज़ देखें ... developer.apple.com/library/ios/documentation/Cocoa/Reference/… :
मैट गैलाघर

5
फिर, कोई अपवाद हैंडलिंग का मतलब अपनी सभी अंतर्निहित समस्याओं के साथ दो-चरण ऑब्जेक्ट निर्माण नहीं है। Stroustrup.com/except.pdf देखें ।
फिल

2
fatalError(...)साथ ही एक ही है।
Holex

8
जितना मुझे स्विफ्ट पसंद है, मुझे लगता है कि यह एक भयावह पसंद है, और कुछ परिणामों का स्वाद था, वे इस चूक के साथ आग से खेल रहे हैं ...
Rob

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

69

9 जून 2015 को अपडेट करें - बहुत महत्वपूर्ण

स्विफ्ट 2.0 के साथ आता है try, throwऔर catchखोजशब्दों और सबसे रोमांचक है:

स्विफ्ट स्वचालित रूप से ऑब्जेक्टिव-सी तरीकों का अनुवाद करता है जो स्विफ्ट की मूल त्रुटि हैंडलिंग कार्यक्षमता के अनुसार त्रुटि फेंकने वाले तरीकों में त्रुटियां पैदा करता है।

नोट: वे विधियाँ जो त्रुटियों का उपभोग करती हैं, जैसे प्रतिनिधि विधियाँ या विधियाँ जो NSError ऑब्जेक्ट तर्क के साथ पूरा हैंडलर लेती हैं, स्विफ्ट द्वारा आयात किए जाने पर फेंकने वाली विधियाँ नहीं बनती हैं।

इसके अंश: Apple Inc. "कोको और ऑब्जेक्टिव-सी (स्विफ्ट 2 प्रीलेयरेज) के साथ स्विफ्ट का उपयोग करना।" iBooks।

उदाहरण: (पुस्तक से)

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success && error){
    NSLog(@"Error: %@", error.domain);
}

स्विफ्ट में बराबर होगा:

let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("path/to/file")
do {
    try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
    print ("Error: \(error.domain)")
}

त्रुटि फेंकना:

*errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo: nil]

स्वचालित रूप से फोन करने वाले को प्रचारित किया जाएगा:

throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)

Apple किताबों से, द स्विफ्ट प्रोग्रामिंग लैंग्वेज से ऐसा लगता है कि त्रुटियों को एनम का उपयोग करना चाहिए।

यहाँ पुस्तक से एक उदाहरण है।

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

से: Apple Inc. "स्विफ्ट प्रोग्रामिंग लैंग्वेज।" iBooks। https://itun.es/br/jEUH0.l

अपडेट करें

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

यहाँ पुस्तक से एक खिंचाव है:

उदाहरण के लिए, नीचे दी गई कोड सूची में, पहली और दूसरी पंक्तियों को निष्पादित नहीं किया जाता है क्योंकि लंबाई संपत्ति और विशेषताएंडइंडेक्स: विधि एनएसडीट ऑब्जेक्ट पर मौजूद नहीं है। MyLength निरंतर एक वैकल्पिक Int होने का अनुमान है, और शून्य पर सेट है। आप उस पद्धति के परिणाम को सशर्त रूप से अनचेक करने के लिए एक if-let स्टेटमेंट का उपयोग कर सकते हैं, जो ऑब्जेक्ट पर प्रतिक्रिया नहीं दे सकता है, जैसा कि लाइन तीन पर दिखाया गया है

let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
    println("Found \(fifthCharacter) at index 5")
}

इसके अंश: Apple Inc. "कोको और उद्देश्य-सी के साथ स्विफ्ट का उपयोग करना।" iBooks। https://itun.es/br/1u3-0.l


और किताबें आपको उद्देश्य-सी (NSError Object) से कोको त्रुटि पैटर्न का उपयोग करने के लिए प्रोत्साहित करती हैं

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

var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
    encoding: NSUTF8StringEncoding,
    error: &writeError)
if !written {
    if let error = writeError {
        println("write failure: \(error.localizedDescription)")
    }
}

इसके अंश: Apple Inc. "कोको और उद्देश्य-सी के साथ स्विफ्ट का उपयोग करना।" iBooks। https://itun.es/br/1u3-0.l


अंतिम कथन के लिए, यह होना चाहिए: do {try myString.writeToFile (पथ, एटोमिकली: ट्रू, एन्कोडिंग: NSUTF8StringEncoding)} कैच को NSError के रूप में कैच दें {प्रिंट (त्रुटि)}
Jacky

1
@ जैकी हाँ, यह स्विफ्ट 2.0 के लिए सच है, हालांकि यह उत्तर स्विफ्ट 2.0 की रिलीज से पहले लिखा गया था, मैंने स्विफ्ट 2.0 में नए तरीके के हैंडल त्रुटियों को दिखाने के लिए उत्तर को अपडेट किया। मैं इस तरह से संदर्भ देने के बारे में सोच रहा था, लेकिन मैं केवल स्विफ्ट 2.0 का उपयोग करने के लिए पूरे उत्तर को अपडेट करने पर विचार करूंगा
Guilherme Torres Castro

12

ऑब्जेक्टिव-सी के दृष्टिकोण के समान स्विफ्ट में कोई अपवाद नहीं हैं।

विकास में, आप assertकिसी भी त्रुटि को पकड़ने के लिए उपयोग कर सकते हैं, जो उत्पादन में जाने से पहले निश्चित हो सकती है, और इसे ठीक करने की आवश्यकता है।

क्लासिक NSErrorदृष्टिकोण को बदल नहीं दिया जाता है, आप एक भेजते हैं NSErrorPointer, जो आबादी में हो जाता है।

संक्षिप्त उदाहरण:

var error: NSError?
var contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/Users/leandros", error: &error)
if let error = error {
    println("An error occurred \(error)")
} else {
    println("Contents: \(contents)")
}

6
इससे एक दो सवाल उठते हैं: क्या होता है जब ओब्जेक कोड जिसे हम स्विफ्ट से बुलाते हैं, वास्तव में एक अपवाद फेंकता है, और क्या एनएसईआरओआर हमारी सार्वभौमिक त्रुटि वस्तु है जैसे ओबजेक?
एमडीजे

1
क्या यह स्विफ्ट के साथ जीवन का सिर्फ एक तथ्य है कि इनिशियलाइज़र असफल हो सकते हैं या नहीं?
फिल

11
अपवाद हैंडलिंग बल्कि गंदा दिखाई देता है
ताश पेमहिवा

27
हाँ, जब आपको सिर्फ दुर्घटना हो सकती है, तो अपवादों की ज़रूरत किसे होगी? या आपके द्वारा घोषित सभी कार्यों में तर्क के रूप में एक NSError ** डालें? ताकि प्रत्येक पहले महीने के लिए f();g();बन जाए f(&err);if(err) return;g(&err);if(err) return;, फिर वह बस बन जाएf(nil);g(nil);hopeToGetHereAlive();
hariseldon78

2
यह उत्तर पुराना है (स्विफ्ट अब अपवादों का समर्थन करता है) और गलत (ऑब्जेक्टिव-सी अपवादों का समर्थन करता है।
Rog

11

अनुशंसित 'स्विफ्ट वे' है:

func write(path: String)(#error: NSErrorPointer) -> Bool { // Useful to curry error parameter for retrying (see below)!
    return "Hello!".writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: error)
}

var writeError: NSError?
let written = write("~/Error1")(error: &writeError)
if !written {
    println("write failure 1: \(writeError!.localizedDescription)")
    // assert(false) // Terminate program
}

हालाँकि, मैं कोशिश करना / पकड़ना पसंद करता हूं क्योंकि मुझे इसका पालन करना आसान लगता है क्योंकि यह अंत में एक अलग ब्लॉक में त्रुटि हैंडलिंग को स्थानांतरित करता है, इस व्यवस्था को कभी-कभी "गोल्डन पाथ" कहा जाता है। भाग्यशाली आप इसे बंद करने के साथ कर सकते हैं:

TryBool {
    write("~/Error2")(error: $0) // The code to try
}.catch {
    println("write failure 2: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

इसके अलावा रिट्रीट सुविधा को जोड़ना आसान है:

TryBool {
    write("~/Error3")(error: $0) // The code to try
}.retry {
    println("write failure 3 on try \($1 + 1): \($0!.localizedDescription)")
    return write("~/Error3r")  // The code to retry
}.catch {
    println("write failure 3 catch: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

TryBool के लिए लिस्टिंग है:

class TryBool {
    typealias Tryee = NSErrorPointer -> Bool
    typealias Catchee = NSError? -> ()
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return self.retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) {
        var error: NSError?
        for numRetries in 0...retries { // First try is retry 0
            error = nil
            let result = tryee(&error)
            if result {
                return
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        catchee(error)
    }
}

आप बूल मान के बजाय वैकल्पिक लौटे मान के परीक्षण के लिए एक समान वर्ग लिख सकते हैं:

class TryOptional<T> {
    typealias Tryee = NSErrorPointer -> T?
    typealias Catchee = NSError? -> T
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) -> T {
        var error: NSError?
        for numRetries in 0...retries {
            error = nil
            let result = tryee(&error)
            if let r = result {
                return r
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        return catchee(error)
    }
}

TryOptional संस्करण एक गैर-वैकल्पिक रिटर्न प्रकार लागू करता है जो बाद की प्रोग्रामिंग को आसान बनाता है, जैसे 'स्विफ्ट वे:

struct FailableInitializer {
    init?(_ id: Int, error: NSErrorPointer) {
        // Always fails in example
        if error != nil {
            error.memory = NSError(domain: "", code: id, userInfo: [:])
        }
        return nil
    }
    private init() {
        // Empty in example
    }
    static let fallback = FailableInitializer()
}

func failableInitializer(id: Int)(#error: NSErrorPointer) -> FailableInitializer? { // Curry for retry
    return FailableInitializer(id, error: error)
}

var failError: NSError?
var failure1Temp = failableInitializer(1)(error: &failError)
if failure1Temp == nil {
    println("failableInitializer failure code: \(failError!.code)")
    failure1Temp = FailableInitializer.fallback
}
let failure1 = failure1Temp! // Unwrap

TryOptional का उपयोग करना:

let failure2 = TryOptional {
    failableInitializer(2)(error: $0)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

let failure3 = TryOptional {
    failableInitializer(3)(error: $0)
}.retry {
    println("failableInitializer failure, on try \($1 + 1), code: \($0!.code)")
    return failableInitializer(31)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

नोट ऑटो-अलॉटिंग।


7

संपादित करें: हालांकि यह उत्तर काम करता है, यह स्विफ्ट में किए गए ऑब्जेक्टिव-सी से थोड़ा अधिक है। इसे स्विफ्ट 2.0 में बदलाव करके अप्रचलित कर दिया गया है। ऊपर गिलेहार्म टोरेस कास्त्रो का जवाब स्विफ्ट में त्रुटियों से निपटने के पसंदीदा तरीके से बहुत अच्छा परिचय है। VOS

यह थोड़ा समझ में आया, लेकिन मुझे लगता है कि मैंने इसे मार दिया है। हालांकि यह बदसूरत लगता है। ऑब्जेक्टिव-सी संस्करण पर एक पतली त्वचा से ज्यादा कुछ नहीं।

NSError पैरामीटर के साथ एक फ़ंक्शन कॉल करना ...

var fooError : NSError ? = nil

let someObject = foo(aParam, error:&fooError)

// Check something was returned and look for an error if it wasn't.
if !someObject {
   if let error = fooError {
      // Handle error
      NSLog("This happened: \(error.localizedDescription)")
   }
} else {
   // Handle success
}`

त्रुटि पैरामीटर लेने वाले फ़ंक्शन को लिखना ...

func foo(param:ParamObject, error: NSErrorPointer) -> SomeObject {

   // Do stuff...

   if somethingBadHasHappened {
      if error {
         error.memory = NSError(domain: domain, code: code, userInfo: [:])
      }
      return nil
   }

   // Do more stuff...
}


5

उद्देश्य सी के आसपास बुनियादी आवरण जो आपको पकड़ने की सुविधा प्रदान करता है। https://github.com/williamFalcon/SwiftTryCatch

जैसे उपयोग करें:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})

अच्छा विचार। लेकिन जो इसका उपयोग करने का निर्णय लेते हैं, उन्हें यह ध्यान रखना चाहिए कि जब एक अपवाद को फेंक दिया जाता है, तो कोशिश ब्लॉक में आवंटित वस्तुओं को निपटाया नहीं जाता है। यह ज़ोंबी वस्तुओं की समस्याओं का कारण बन सकता है और RAII के प्रत्येक उपयोग से छेड़छाड़ की जाती है (ऑटो-अनलॉक, ऑटो-एसक्यूएल-कमिट, ऑटो-स्क्वायर-रोलबैक ...)। शायद c ++ हमें "runAtExit" के कुछ रूप में मदद कर सकता है?
hariseldon78 19

अद्यतन: मुझे सिर्फ यह पता चला है कि अपवाद को फेंकने में वस्तुओं की रिहाई को सक्षम करने के लिए एक झंडे में है: -fobjc-arc-अपवाद। मुझे कोशिश करनी चाहिए कि यह अभी भी लिपटे हुए संस्करण के साथ काम करता है (मुझे लगता है कि यह चाहिए)
hariseldon78

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

1
आपके नियंत्रण से बाहर स्थितियां हो सकती हैं। उदाहरण के लिए, गलत प्रारूप में जर्सन को पार्स करना।
विलियम फाल्कन

3

यह तेजी से 2.0 के लिए एक अद्यतन जवाब है। मैं java की तरह आगे की सुविधा संपन्न एरर हैंडलिंग मॉडल देख रहा हूँ। अंत में, उन्होंने खुशखबरी की घोषणा की। यहाँ

हैंडलिंग मॉडल में त्रुटि: स्विफ्ट 2.0 में नया एरर हैंडलिंग मॉडल सहज रूप से परिचित , कोशिश, फेंक और कीवर्ड को पकड़ने के साथ स्वाभाविक लगेगा । सबसे अच्छा, यह Apple SDKs और NSError के साथ पूरी तरह से काम करने के लिए डिज़ाइन किया गया था। वास्तव में, NSError एक Swift के ErrorType के अनुरूप है। आप निश्चित रूप से इसके बारे में अधिक सुनने के लिए स्विफ्ट में व्हाट्स न्यू पर WWDC सत्र देखना चाहते हैं।

जैसे:

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}

3

के रूप में गुइलहर्मे टोरेस कास्त्रो ने कहा, स्विफ्ट 2.0 में, try, catch, doप्रोग्रामिंग में इस्तेमाल किया जा सकता।

उदाहरण के लिए, कोरडाटा में डेटा विधि, &errorएक पैरामीटर के रूप में डालने के बजाय managedContext.executeFetchRequest(fetchRequest, error: &error), अब हमें केवल उपयोग की आवश्यकता है managedContext.executeFetchRequest(fetchRequest)और फिर त्रुटि को संभालना होगा try, catch( Apple दस्तावेज़ लिंक )

do {
   let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
   if let results = fetchedResults{
      people = results
   }
} catch {
   print("Could not fetch")
}

यदि आप पहले से ही xcode7 बीटा डाउनलोड कर चुके हैं। दस्तावेज़ीकरण और एपीआई संदर्भ में फेंकने वाली त्रुटियों को खोजने की कोशिश करें और पहला प्रदर्शन परिणाम चुनें, यह एक मूल विचार देता है कि इस वाक्यविन्यास वाक्य के लिए क्या किया जा सकता है। हालाँकि, पूरी तरह से प्रलेखन अभी तक कई एपीआई के लिए पोस्ट नहीं है।

अधिक फैंसी त्रुटि हैंडलिंग तकनीकों में पाया जा सकता है

व्हाट्स न्यू इन स्विफ्ट (2015 सत्र 106 28 मीटर 30)



1

अपवाद को संभालने के लिए अच्छा और सरल काम: TryCatchFinally-Swift

कुछ अन्य लोगों की तरह यह उद्देश्य C अपवाद सुविधाओं के आसपास लपेटता है।

इसे इस तरह उपयोग करें:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}

मैंने एक नमूना जोड़ा है :)
मोर्टन होल्मगार्ड

यह शायद लेखकों की राय का उल्लेख करने लायक है: "चेतावनी: यह मज़ेदार और बुराई के लिए एक हैक है। इसका उपयोग करने के प्रलोभन का विरोध करें।"
jbat100

1

स्विफ्ट 2 के साथ शुरू करना, जैसा कि दूसरों ने पहले ही उल्लेख किया है, त्रुटि हैंडलिंग सबसे अच्छी तरह से do / try / catch और ErrorType नंबरों के उपयोग के माध्यम से पूरा किया गया है। यह सिंक्रोनस तरीकों के लिए काफी अच्छी तरह से काम करता है, लेकिन अतुल्यकालिक त्रुटि से निपटने के लिए थोड़ी चतुराई की आवश्यकता होती है।

इस लेख में इस समस्या के लिए एक महान दृष्टिकोण है:

https://jeremywsherman.com/blog/2015/06/17/using-swift-throws-with-completion-callbacks/

संक्षेप में:

// create a typealias used in completion blocks, for cleaner code
typealias LoadDataResult = () throws -> NSData

// notice the reference to the typealias in the completionHandler
func loadData(someID: String, completionHandler: LoadDataResult -> Void)
    {
    completionHandler()
    }

फिर, उपरोक्त विधि के लिए कॉल इस प्रकार होगा:

self.loadData("someString",
    completionHandler:     
        { result: LoadDataResult in
        do
            {
            let data = try result()
            // success - go ahead and work with the data
            }
        catch
            {
            // failure - look at the error code and handle accordingly
            }
        })

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


0

मैंने जो देखा है, वह यह है कि डिवाइस की प्रकृति के कारण आप उपयोगकर्ता पर संदेश भेजने में गुप्त त्रुटि का एक गुच्छा फेंकना नहीं चाहते हैं। यही कारण है कि अधिकांश फ़ंक्शन वैकल्पिक मान लौटाते हैं तो आप वैकल्पिक को अनदेखा करने के लिए कोड करते हैं। यदि कोई फ़ंक्शन वापस आता है जिसका अर्थ है कि यह विफल हो गया है तो आप एक संदेश या जो कुछ भी कर सकते हैं।


1
शून्य लौटना त्रुटि की प्रकृति पर कोई जानकारी नहीं देता है। यदि कोई त्रुटि वस्तु तब मिलती है जब कोई त्रुटि तब होती है, तो त्रुटि के आधार पर, प्रोग्रामर इसे अनदेखा करना, इसे संभालना, इसे बबल करना या "एक संदेश पॉप या जो भी हो" चुन सकता है। ज्ञान ही शक्ति है।
विंस ओ'सुल्लिवन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.