11

हे अपर में एनएसईआरआर बनाम अपवाद हैंडलिंग का उपयोग करना। मैं ऐप्पल के सुझावों पर पढ़ रहा हूं कि एनएसईआरर बनाम @ try/@ catch/@ अंत में कब/कहां/कैसे उपयोग करें। अनिवार्य रूप से, मेरी धारणा यह है कि ऐप्पल अनपेक्षित त्रुटि स्थितियों में प्रोग्राम निष्पादन को रोकने के लिए एक तंत्र के रूप में छोड़कर अपवाद हैंडलिंग भाषा संरचनाओं के उपयोग से बचने के लिए सबसे अच्छा सोचता है (शायद कोई ऐसी स्थिति का उदाहरण दे सकता है?)कोको ऐप्स

मैं आ गया जावा से, जहां अपवादों को संभालने के लिए अपवाद होते हैं। माना जाता है कि, मैं अभी भी जावा विचारस्थान में हूं, लेकिन मैं धीरे-धीरे उन सभी एनएसईआरआरआर के साथ पकड़ने के लिए आ रहा हूं।

एक चीज जिसे मैं लटका रहा हूं वह एक त्रुटि होने पर स्मृति को साफ करने का कार्य है। कई परिस्थितियों में (उदाहरण के लिए सी, सी ++ लाइब्रेरीज़, कोरफाउंडेशन इत्यादि का उपयोग करना ..) आपके पास बहुत मेमोरी क्लीनअप है जो किसी त्रुटि के कारण किसी फ़ंक्शन को तोड़ने से पहले करने की आवश्यकता है।

यहां एक उदाहरण है जिसे मैंने पकाया है जो सटीक रूप से उन परिस्थितियों को प्रतिबिंबित करता है जो मुझे सामना कर रहा है। कुछ काल्पनिक डेटा संरचनाओं का उपयोग करके, फ़ंक्शन एक फ़ाइल हैंडल खोलता है और 'MyFileRefInfo' ऑब्जेक्ट बनाता है जिसमें फ़ाइल के साथ क्या करना है इसके बारे में जानकारी शामिल है। फ़ाइल हैंडल बंद होने से पहले फ़ाइल के साथ कुछ सामान किया जाता है और संरचना के लिए स्मृति मुक्त हो जाती है। एप्पल के सुझावों का प्रयोग मैं इस विधि है:

- (BOOL)doSomeThingsWithFile:(NSURL *)filePath error:(NSError **)error 
{ 
    MyFileReference inFile; // Lets say this is a CF struct that opens a file reference 
    MyFileRefInfo *fileInfo = new MyFileRefInfo(...some init parameters...); 

    OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile); 

    if(err != NoErr) 
    { 
    *error = [NSError errorWithDomain:@"myDomain" code:99 userInfo:nil]; 
    delete fileInfo; 
    return NO; 
    } 

    err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo); 

    if(err != NoErr) 
    { 
    *error = [NSError errorWithDomain:@"myDomain" code:100 userInfo:nil]; 
    CloseFileHandle(inFile); // if we don't do this bad things happen 
    delete fileInfo; 
    return NO; 
    }  

    err = DoSomeOtherStuffWithTheFile(inFile,fileInfo); 

    if(err != NoErr) 
    { 
    *error = [NSError errorWithDomain:@"myDomain" code:101 userInfo:nil]; 
    CloseFileHandle(inFile); // if we don't do this bad things happen 
    delete fileInfo; 
    return NO; 
    }  

    CloseFileHandle(inFile); 
    delete fileInfo; 
    return YES; 

} 
अब

.. मेरी जावा तर्क मुझसे कहता है कि यह बेहतर होगा आज़माएं/कैच/अंत में संरचना के रूप में इस की स्थापना की और फ़ाइल हैंडल बंद करने के लिए सभी कॉल्स डाल करने के लिए और आखिरकार ब्लॉक में मुफ्त मेमोरी।

तो जैसा

..

... 

    @try 
    { 
     OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile); 
     if(err != NoErr) 
     { 
     ... throw some exception complete with error code and description ... 
     } 

     err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo); 

     if(err != NoErr) 
     { 
     ... throw some exception ... 
     } 

     ... etc ...   
} 
@catch(MyException *ex) 
{ 
     *error = [NSError errorWithDomain:@"myDomain" code:[ex errorCode] userInfo:nil]; 
     return NO; 
} 
@finally 
{ 
     CloseFileHandle(inFile); // if we don't do this bad things happen 
     delete fileInfo; 
} 
return YES; 

Am मैं यह सोच कर कि यह कम अनावश्यक कोड के साथ एक अधिक सुरुचिपूर्ण समाधान है में पागल हो? क्या मुझे कुछ याद आया?

+0

उदाहरण को थोड़ा सा सरल बनाया गया हो सकता है, लेकिन यह जांचना न भूलें कि त्रुटि इसे आवंटित करने से पहले पूर्ण नहीं है, क्योंकि जब आप त्रुटियों की परवाह नहीं करते हैं तो सम्मेलन त्रुटि चर के स्थान पर NULL भेजना है । यदि आप इस मामले में न्यूल को अस्वीकार करते हैं, तो आप बस गलती का कारण बनेंगे (यह एक शून्य ऑब्जेक्ट मैसेजिंग की तरह नहीं है)। –

उत्तर

3

उद्देश्य-सी में अपवाद ऐतिहासिक रूप से 'भारी' हैं, एक कोशिश ब्लॉक में प्रवेश करने की लागत, फेंकने की लागत, अंततः उपयोग करने की लागत आदि के परिणामस्वरूप, कोको डेवलपर्स ने आम तौर पर अपवादों से बचा है 'ओह नहीं, आकाश गिर रहा है' परिस्थितियों के प्रकार - यदि कोई फ़ाइल गुम है, तो एक एनएसईआरआरआर का उपयोग करें, लेकिन यदि कोई फाइल सिस्टम और नकारात्मक स्मृति की ऋणात्मक मात्रा नहीं है, तो यह एक अपवाद है।

यह ऐतिहासिक दृश्य है। लेकिन यदि आप 10.5 या नए पर 64-बिट ऐप बना रहे हैं, तो अपवाद आर्किटेक्चर को 'शून्य लागत' के रूप में लिखा गया है, जिसका अर्थ यह हो सकता है कि ऐतिहासिक दृश्य अब प्रासंगिक नहीं है। जैसा कि कुछ भी के साथ है, यह विभिन्न कारकों के लिए आता है - यदि एक तरह से काम करना आपके लिए अधिक स्वाभाविक है और आपको अधिक तेज़ी से खत्म करने देगा, और यदि आपको इसके साथ किसी भी प्रदर्शन से संबंधित समस्याओं का अनुभव नहीं होता है, और यदि थोड़ा हो 'पारंपरिक' उद्देश्य-सी कोड के साथ असंगत आपको परेशान नहीं करता है ... तो अपवादों का उपयोग न करने का कोई कारण नहीं है।

+0

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

+0

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

+0

क्या आप मुझे एक उदाहरण दे सकते हैं कि आपको कैसे भुगतान करना होगा? जब तक आप ऐसी परिस्थिति में न हों जहां आप एक सिस्टम एपीआई * के माध्यम से * अपवाद फेंकने की कोशिश कर रहे हैं, तो मुझे नहीं लगता कि आपके अपने कोड में अपवादों का उपयोग करने से कोई नकारात्मक बातचीत हो रही है। – Skirwan

12

अनिवार्य रूप से, मेरी धारणा है कि एप्पल यह अनपेक्षित त्रुटि स्थितियों में प्रोग्राम निष्पादन को रोकने के लिए एक तंत्र के रूप में छोड़कर अपवाद हैंडलिंग भाषा निर्माणों के उपयोग से बचने के लिए सबसे अच्छा सोचता है (शायद किसी को ऐसी स्थिति का एक उदाहरण दे सकता है?)

यह मेरी पूरी छाप नहीं है। मैंने सोचा कि ऐप्पल वास्तव में असाधारण स्थितियों के लिए अपवादों का उपयोग करता है, और अपेक्षित असफलताओं के लिए एनएसईआरआरआर का सुझाव देता है। चूंकि आप जावा से आते हैं, मुझे लगता है कि एनएसईआरर -> java.lang.Exception, और Obj-C अपवाद -> java.lang.RuntimeException। जब प्रोग्रामर ने कुछ गलत किया (उदाहरण के लिए, एक एपीआई गलत तरीके से इस्तेमाल किया गया), तो ओबीजे-सी अपवाद का उपयोग करें, और अपेक्षित विफलता होने पर एनएसईआरआरआर का उपयोग करें (उदाहरण के लिए दूरस्थ सर्वर नहीं मिला)।

बेशक, यह सिर्फ ऐप्पल की स्थिति की मेरी व्याख्या है। मैं, दूसरी तरफ, अपवादों की तरह!

+2

आपने ऐप्पल की स्थिति को सही तरीके से कब्जा कर लिया है। त्रुटियां पूर्वदर्शी समस्याएं हैं जिन्हें आप शायद उपयोगकर्ता को पेश करना चाहते हैं। अपवादों को या तो कभी नहीं होना चाहिए या हमेशा पकड़ा जाना चाहिए। कोको को इसके चारों ओर डिज़ाइन किया गया है, जैसा कि ऐपकिट की नई त्रुटि-प्रस्तुति प्रणाली द्वारा उदाहरण दिया गया है। http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/ErrorHandling/ErrorHandling.html http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Exceptions/Exceptions .html –

+0

ठीक है, मुझे लगता है कि मैं समझता हूं। ऐसा लगता है जैसे ऐप्पल हमें फ़ंक्शन कॉल स्टैक पर त्रुटियों को संप्रेषित करने के दो तरीके दे रहा है, और यह कि दो तरीकों से एनएसईआरआरआर कोको द्वारा समर्थित एक बेहतर तरीका है। मैं उस विधि के साथ जाना चाहता हूं जो बेहतर समर्थित है .. लेकिन अपवादों के नियंत्रण प्रवाह की विशेषताएं कम अनावश्यक कोड के लिए लगती हैं। ओबज-सी/कोको में कुछ ऐसा मौका है जो इसे संबोधित करता है? –

+0

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

17

डैनियल का जवाब सही है, लेकिन इस सवाल के बजाय एक और अधिक बदसूरत जवाब का हकदार है।

एक अपवाद फेंकने पर केवल अपवाद फेंक दें।

त्रुटि शर्तों को संप्रेषित करते समय एनएसईआरआरआर का उपयोग करें।

ऐप्पल के ढांचे में किसी फ्रेम के माध्यम से फेंक दिया गया कोई भी अपवाद अपरिभाषित व्यवहार में हो सकता है।

देव केंद्र में Exceptions programming topic document उपलब्ध है।

+0

मुझे खुशी है कि आप इसे एक उत्तर में डाल देंगे, क्या मैं +2 :) –

2

More iPhone 3 Development के अनुसार डेव मार्क और जेफ लीमारचे द्वारा अपवादों का उपयोग केवल वास्तव में असाधारण परिस्थितियों के लिए किया जाता है और आमतौर पर आपके कोड में समस्या का संकेत मिलता है। आपको रन-ऑफ-द-मिल त्रुटि स्थिति की रिपोर्ट करने के लिए अपवादों का कभी भी उपयोग नहीं करना चाहिए। जावा और सी ++ जैसी कई अन्य भाषाओं की तुलना में अपवादों का उद्देश्य उद्देश्य-सी में बहुत कम आवृत्ति के साथ उपयोग किया जाता है।

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

एक उदाहरण है जहाँ आप एक अपवाद का प्रयोग करेंगे है:

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

NSException *ex = [NSException exceptionWithName:@"Abstract Method Not Overridden" reason:NSLocalizedString(@"You MUST override the save method", @"You MUST override the save method") userInfo:nil]; 
[ex raise]; 

क्योंकि समस्या एक समस्या उपयोगकर्ता ठीक करने में सक्षम हो सकता है बजाय एक प्रोग्रामर गलती है, तो एक अपवाद का उपयोग करें।

+0

कर सकता हूं यदि अपवाद का उपयोग करने का एकमात्र मामला था, तो अपवाद भी होने के लिए क्या बिंदु होगा? क्या आप सिर्फ त्रुटि प्रिंट नहीं करेंगे और बाहर निकलेंगे() - जैसे अपवाद मौजूद होने से पहले ओएल 'सी दिनों में? –

+0

इस सवाल पूछने के लिए धन्यवाद। अपवादों का उपयोग करने के लाभ यहां वर्णित हैं: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/ControllingAppResponse.html। आप NSExceptions का उपयोग "एक वर्णनात्मक लॉग और कंसोल पर एक स्टैक ट्रेस प्रिंट करने के लिए कर सकते हैं जब ऐसी त्रुटि (अनचेक एनएसईएक्सप्शन) होती है" और "परिणामी अचानक समाप्ति को रोकने के लिए त्रुटि को इस तरह से संभाल लें।" –

+0

हां। लेकिन आप आम तौर पर एक प्रोग्रामिंग गलती को संभालना नहीं चाहते हैं ... इस तरह से रोकने के लिए ... अचानक समाप्त " –