ऑब्जेक्टिव-सी / कोको में एक अपवाद फेंकना


जवाबों:


528

मैं [NSException raise:format:]निम्नानुसार उपयोग करता हूं :

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];

9
मैं इस तरीके को पसंद करता हूं @throw([NSException exceptionWith…])क्योंकि इसे अधिक संक्षिप्त रूप में दृष्टिकोण के लिए अपील किया गया है ।
सैम सॉफ्स


26
मैं आम तौर पर इसे भी पसंद करता हूं, लेकिन एक गोचा है। बस मेरा वर्तमान संस्करण Xcode हो सकता है, लेकिन [NSException raise ...] सिंटैक्स को Parser द्वारा किसी विधि से निकलने वाले पथ के रूप में पहचाना नहीं जाता है, जो मान लौटाता है। मैं इस वाक्यविन्यास का उपयोग करते समय चेतावनी "नियंत्रण गैर-शून्य फ़ंक्शन के अंत तक पहुंच सकता हूं" देख रहा हूं, लेकिन @throw ([NSException अपवाद ...]) सिंटैक्स के साथ, पार्सर एक निकास के रूप में पहचानता है और चेतावनी प्रदर्शित नहीं करता है।
मैटोरब

1
@mpstx मैं हमेशा आपके द्वारा दिए गए कारण के लिए सिंटैक्स का उपयोग करता हूं (जो कि Xcode 4.6 में दो साल बाद भी प्रासंगिक है, और शायद हमेशा रहेगा)। IDE को पहचानने के बाद कि अपवाद को छोड़ना एक फ़ंक्शन निकास बिंदु है, यदि आप चेतावनी से बचना चाहते हैं।
मार्क एमी जूल

FWIW मैं यह देख रहा हूँ कि @ try / @ catch ब्लॉक्स के परिणामस्वरूप "गैर-शून्य फ़ंक्शन के अंत में नियंत्रण" चेतावनियों के लिए भी एक गलत-नकारात्मक परिणाम आता है (चेतावनियाँ प्रदर्शित नहीं होती हैं (यानी चेतावनी तब प्रदर्शित नहीं होनी चाहिए जब यह होनी चाहिए)
ब्रायन गेर्स्टल

256

यहाँ सावधानी का एक शब्द। उद्देश्य-सी में, कई समान भाषाओं के विपरीत, आपको आम तौर पर सामान्य त्रुटि स्थितियों के लिए अपवादों के उपयोग से बचने का प्रयास करना चाहिए जो सामान्य ऑपरेशन में हो सकते हैं।

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

Apple के वैचारिक अपवाद से निपटने के दस्तावेज वही बताते हैं, लेकिन अधिक शब्दों के साथ: "महत्वपूर्ण: आपको प्रोग्रामिंग या अप्रत्याशित रनटाइम त्रुटियों के लिए अपवादों के उपयोग को आरक्षित करना चाहिए जैसे कि आउट-ऑफ-बाउंड्स संग्रह पहुंच, अपरिवर्तनीय वस्तुओं को म्यूट करने का प्रयास, एक अवैध संदेश भेजना , और विंडो सर्वर से कनेक्शन खोने पर। आप आमतौर पर अपवादों के साथ इस प्रकार की त्रुटियों का ध्यान रखते हैं जब कोई एप्लिकेशन रनटाइम के बजाय बनाया जा रहा होता है। [.....] अपवादों के बजाय, त्रुटि ऑब्जेक्ट्स (NSError) और कोकोआ त्रुटि-वितरण तंत्र कोकोआ अनुप्रयोगों में अपेक्षित त्रुटियों को संवाद करने का अनुशंसित तरीका है। ”

इसका कारण आंशिक रूप से ऑब्जेक्टिव-सी में प्रोग्रामिंग मुहावरों का पालन करना है (अधिक जटिल मामलों में साधारण मामलों में रिटर्न मानों और उप-संदर्भ मापदंडों (अक्सर NSError वर्ग) का उपयोग करके), आंशिक रूप से अपवादों को फेंकना और पकड़ना बहुत अधिक महंगा है और अंत में (और सबसे महत्वपूर्ण बात) कि ऑब्जेक्टिव-सी अपवाद C के सेटजम्प () और लॉन्गजम्प () फंक्शन्स के आसपास एक पतला आवरण है, जो अनिवार्य रूप से आपकी सावधान मेमोरी हैंडलिंग को गड़बड़ कर रहा है, इस स्पष्टीकरण को देखें ।


11
मुझे लगता है कि यह अधिकांश प्रोग्रामिंग भाषाओं पर लागू होता है: "सामान्य त्रुटि स्थितियों के लिए अपवादों से बचने का प्रयास करें"। जावा में भी यही लागू होता है; अपवादों के साथ उपयोगकर्ता इनपुट त्रुटियों (उदाहरण के लिए) को संभालना बुरा है। न केवल संसाधन उपयोग के कारण, बल्कि कोड स्पष्टता के लिए भी।
चुकंदर 12

6
इससे भी महत्वपूर्ण बात, कोको में अपवाद गैर-वसूली योग्य कार्यक्रम त्रुटियों को इंगित करने के लिए डिज़ाइन किए गए हैं। अन्यथा करना ढांचे के खिलाफ चल रहा है और अपरिभाषित व्यवहार का कारण बन सकता है। देखें stackoverflow.com/questions/3378696/iphone-try-end-try/... जानकारी के लिए।
केपीएम

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

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

1
यह टिप्पणी प्रश्न का उत्तर नहीं देती है। हो सकता है कि ओपी सिर्फ यह जांचने के लिए ऐप को क्रैश करना चाहता है कि दुर्घटना रिपोर्ट फ्रेमवर्क अपेक्षित रूप से काम कर रहा है या नहीं।
साइमन

62
@throw([NSException exceptionWith…])

Xcode @throwस्टेटमेंट्स को फंक्शन एग्जिट पॉइंट्स की तरह returnस्टेटमेंट्स की पहचान करता है। @throwवाक्यविन्यास का उपयोग करने से ग़लतफ़हमी से बचा जाता है " नियंत्रण गैर-शून्य फ़ंक्शन के अंत तक पहुंच सकता है " चेतावनी जो आपको मिल सकती है [NSException raise:…]

इसके अलावा, @throwउन वस्तुओं को फेंकने के लिए इस्तेमाल किया जा सकता है जो कक्षा NSException के नहीं हैं।


11
@ स्टेफ़ थिरियन: सभी विवरणों के लिए डेवलपर. apple.com/documentation/Cocoa/Conceptual/Exception/… देखें । जमीनी स्तर? दोनों काम करेंगे, लेकिन @throw का उपयोग उन वस्तुओं को फेंकने के लिए किया जा सकता है जो कक्षा NSException की नहीं हैं।
ई। रमेश

33

के संबंध में [NSException raise:format:]। जावा बैकग्राउंड से आने वालों के लिए, आपको याद होगा कि जावा एक्सेप्शन और रनटाइम एक्सेप्शन के बीच अंतर करता है। अपवाद एक जाँच अपवाद है, और RuntimeException अनियंत्रित है। विशेष रूप से, जावा "सामान्य त्रुटि स्थितियों" के लिए जाँच किए गए अपवादों का उपयोग करने का सुझाव देता है और "क्रमादेशित त्रुटि के कारण रनटाइम त्रुटियों" के लिए अनियंत्रित अपवादों का उपयोग करता है। ऐसा लगता है कि ऑब्जेक्टिव-सी अपवादों का उपयोग उन्हीं स्थानों पर किया जाना चाहिए जहां आप अनियंत्रित अपवाद का उपयोग करेंगे, और त्रुटि कोड रिटर्न मान या NSError मान उन जगहों पर पसंद किए जाते हैं जहां आप एक चेक किए गए अपवाद का उपयोग करेंगे।


1
हाँ यह सही है (4 साल के बाद: D), अपनी खुद की त्रुटि वर्ग ABCError बनाएं जो NSError वर्ग से फैली हुई है और NSException के बजाय जाँच किए गए अपवादों के लिए उपयोग करें। NSException को उठाएं जहां प्रोग्रामर त्रुटियां (अप्रत्याशित स्थिति जैसे संख्या प्रारूप समस्या) होती है।
चतुर्थी

15

मुझे लगता है कि यह आपके अपने वर्ग के साथ Nthxception का विस्तार करने वाले @throw का उपयोग करने के लिए सुसंगत है। तो फिर तुम अंततः पकड़ने की कोशिश के लिए एक ही अधिसूचना का उपयोग करें:

@try {
.....
}
@catch{
...
}
@finally{
...
}

ऐप्पल ने यहां बताया कि अपवादों को कैसे फेंकना और संभालना है: कैचिंग एक्सेप्शन


मैं अभी भी कोशिश ब्लॉक में अपवाद अपवाद से दुर्घटनाग्रस्त हो गया
famfamfam

14

ObjC 2.0 के बाद से, Objective-C अपवाद अब C के setjmp () longjmp () के लिए एक आवरण नहीं हैं, और C ++ अपवाद के साथ संगत हैं, @try "निःशुल्क है", लेकिन अपवादों को फेंकना और पकड़ना अधिक महंगा है।

वैसे भी, अभिकथन (NSAssert और NSCAssert मैक्रो परिवार का उपयोग करके) NSException को फेंक देते हैं, और उस संत को रीस राज्यों के रूप में उपयोग करने के लिए।


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

8

अपवादों के बजाय विफलताओं का संचार करने के लिए NSError का उपयोग करें।

NSError के बारे में त्वरित बिंदु:

  • NSError C स्टाइल त्रुटि कोड (पूर्णांक) के लिए मूल कारण को स्पष्ट रूप से पहचानने की अनुमति देता है और त्रुटि हैंडलर को त्रुटि को दूर करने की अनुमति देता है। आप NSError उदाहरणों में SQLite जैसे C पुस्तकालयों से त्रुटि कोड बहुत आसानी से लपेट सकते हैं।

  • NSError में एक ऑब्जेक्ट होने का लाभ भी है और इसके userInfo डिक्शनरी के सदस्य के साथ अधिक विस्तार से त्रुटि का वर्णन करने का एक तरीका प्रदान करता है।

  • लेकिन सभी के सर्वश्रेष्ठ, NSError CANNOT को फेंका नहीं जा सकता है, इसलिए यह अन्य भाषाओं के विपरीत त्रुटि से निपटने के लिए एक अधिक सक्रिय दृष्टिकोण को प्रोत्साहित करता है, जो केवल गर्म आलू को आगे और आगे कॉल स्टैक को फेंकते हैं जिस बिंदु पर यह केवल उपयोगकर्ता और उपयोगकर्ता को सूचित किया जा सकता है किसी भी सार्थक तरीके से नहीं संभाला जाता है (यदि आप OOP सूचना के सबसे बड़े सिद्धांत को छिपाने में विश्वास नहीं करते हैं)।

संदर्भ लिंक: संदर्भ


यह टिप्पणी प्रश्न का उत्तर नहीं देती है। हो सकता है कि ओपी केवल यह जांचने के लिए ऐप को क्रैश करना चाहता है कि दुर्घटना रिपोर्ट फ्रेमवर्क अपेक्षित रूप से काम कर रहा है या नहीं।
सिमोन

7

इसे मैंने "द बिग नर्ड रेंच गाइड (4 वें संस्करण)" से सीखा है।

@throw [NSException exceptionWithName:@"Something is not right exception"
                               reason:@"Can't perform this operation because of this or that"
                             userInfo:nil];

ठीक है, लेकिन यह इसके बारे में ज्यादा नहीं बताता है userInfo:nil। :)
C

6

आप ट्राई कैच ब्लॉक में अपवाद बढ़ाने के लिए दो तरीकों का उपयोग कर सकते हैं

@throw[NSException exceptionWithName];

या दूसरी विधि

NSException e;
[e raise];

3

मेरा मानना ​​है कि आपको सामान्य कार्यक्रम प्रवाह को नियंत्रित करने के लिए अपवादों का उपयोग कभी नहीं करना चाहिए। जब भी कुछ मूल्य वांछित मूल्य से मेल नहीं खाते हैं, लेकिन अपवादों को फेंक दिया जाना चाहिए।

उदाहरण के लिए यदि कोई फ़ंक्शन मान को स्वीकार करता है, और उस मान को कभी शून्य होने की अनुमति नहीं है, तो यह अपवाद को फेंकने के लिए ठीक है, फिर कुछ 'स्मार्ट' करने की कोशिश कर रहा है ...

आरआईई


0

आपको केवल अपवादों को फेंकना चाहिए यदि आप खुद को ऐसी स्थिति में पाते हैं जो प्रोग्रामिंग त्रुटि को इंगित करता है, और एप्लिकेशन को चलने से रोकना चाहता है। इसलिए, अपवाद फेंकने का सबसे अच्छा तरीका NSAssert और NSParameterAssert मैक्रोज़ का उपयोग कर रहा है, और यह सुनिश्चित करना है कि NS_BLOCK_ASSERTIONS परिभाषित नहीं है।


0

मामले के लिए नमूना कोड: @throw ([NSException अपवादWithName: ...

- (void)parseError:(NSError *)error
       completionBlock:(void (^)(NSString *error))completionBlock {


    NSString *resultString = [NSString new];

    @try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    resultString = dictFromData[@"someKey"];
    ...


} @catch (NSException *exception) {

      NSLog( @"Caught Exception Name: %@", exception.name);
      NSLog( @"Caught Exception Reason: %@", exception.reason );

    resultString = exception.reason;

} @finally {

    completionBlock(resultString);
}

}

का उपयोग करते हुए:

[self parseError:error completionBlock:^(NSString *error) {
            NSLog(@"%@", error);
        }];

एक और अधिक उन्नत उपयोग-मामला:

- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {

NSString *resultString = [NSString new];

NSException* customNilException = [NSException exceptionWithName:@"NilException"
                                                          reason:@"object is nil"
                                                        userInfo:nil];

NSException* customNotNumberException = [NSException exceptionWithName:@"NotNumberException"
                                                                reason:@"object is not a NSNumber"
                                                              userInfo:nil];

@try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    NSArray * array = dictFromData[@"someArrayKey"];

    for (NSInteger i=0; i < array.count; i++) {

        id resultString = array[i];

        if (![resultString isKindOfClass:NSNumber.class]) {

            [customNotNumberException raise]; // <====== HERE is just the same as: @throw customNotNumberException;

            break;

        } else if (!resultString){

            @throw customNilException;        // <======

            break;
        }

    }

} @catch (SomeCustomException * sce) {
    // most specific type
    // handle exception ce
    //...
} @catch (CustomException * ce) {
    // most specific type
    // handle exception ce
    //...
} @catch (NSException *exception) {
    // less specific type

    // do whatever recovery is necessary at his level
    //...
    // rethrow the exception so it's handled at a higher level

    @throw (SomeCustomException * customException);

} @finally {
    // perform tasks necessary whether exception occurred or not

}

}


-7

सामान्य रूप से उद्देश्य सी में अपवादों का उपयोग नहीं करने का कोई कारण नहीं है यहां तक ​​कि व्यावसायिक नियम अपवादों को भी इंगित करने के लिए। कह सकते हैं कि Apple NSError का उपयोग करता है जो परवाह करता है। ओबज सी एक लंबे समय के आसपास रहा है और एक समय में सभी सी ++ प्रलेखन ने एक ही बात कही है। इसका कारण यह नहीं है कि एक अपवाद को फेंकना और पकड़ना कितना महंगा है, क्या एक अपवाद का जीवनकाल बहुत कम है और ... इसका सामान्य प्रवाह के लिए एक अपवाद है। मैंने अपने जीवन में कभी किसी को यह कहते हुए नहीं सुना, वह आदमी जिसे फेंकने और पकड़ने में लंबा समय लगा।

इसके अलावा, ऐसे लोग हैं जो सोचते हैं कि उद्देश्य C स्वयं बहुत महंगा है और इसके बजाय C या C ++ में कोड है। इसलिए कहा जाता है कि हमेशा NSError का उपयोग करना गलत जानकारी और अपवित्र है।

लेकिन इस थ्रेड के सवाल का अभी तक उत्तर नहीं मिला है कि अपवाद को फेंकने का सबसे अच्छा तरीका क्या है। NSError को वापस करने के तरीके स्पष्ट हैं।

तो यह है: [NSException बढ़ाएँ: ... @throw [[NSException आवंटन] initWithName .... या @throw [[MyCustomException ...?

मैं यहाँ जाँच / अनियंत्रित नियम का उपयोग ऊपर से थोड़ा अलग करता हूँ।

(जावा रूपक का उपयोग करके) यहाँ जाँच / अनियंत्रित के बीच वास्तविक अंतर महत्वपूर्ण है -> क्या आप अपवाद से उबर सकते हैं। और ठीक होने से मेरा मतलब है कि सिर्फ दुर्घटना नहीं।

इसलिए मैं पुनर्प्राप्त अपवादों के लिए @throw के साथ कस्टम अपवाद कक्षाओं का उपयोग करता हूं, क्योंकि इसकी संभावना है कि मेरे पास कुछ ऐप विधि कई @ ब्लॉक ब्लॉक में कुछ प्रकार की विफलताओं की तलाश होगी। उदाहरण के लिए यदि मेरा ऐप एक एटीएम मशीन है, तो मेरे पास "WithdrawalRequestExceedsBalanceException" के लिए एक @catch ब्लॉक होगा।

मैं NSException का उपयोग करता हूं: रनटाइम अपवादों के लिए उठाता हूं क्योंकि मेरे पास अपवाद से पुनर्प्राप्त करने का कोई तरीका नहीं है, सिवाय इसके कि इसे उच्च स्तर पर पकड़ा जाए और लॉग इन किया जाए। और उस के लिए एक कस्टम वर्ग बनाने में कोई मतलब नहीं है।

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


4
मैं इस तरह के सामान्यीकरण वाले बयान बनाने से पहले सर्वर के प्रोग्राम को अपवाद के रूप में त्रुटि मामलों के सामान्य प्रवाह के भाग के रूप में दर्ज करने का प्रयास करने की सलाह दूंगा क्योंकि "सामान्य रूप से उद्देश्य सी में अपवादों का उपयोग नहीं करने का कोई कारण नहीं है"। मानो या न मानो, ओबीजीसी में उच्च प्रदर्शन अनुप्रयोगों (या अनुप्रयोगों के कम से कम भागों) को लिखने के कारण हैं, और अपवादों को आम तौर पर गंभीरता से प्रदर्शन को बाधित करते हैं।
जेनेट

6
कोको में अपवादों का उपयोग न करने के वास्तव में बहुत अच्छे कारण हैं। अधिक के लिए यहां बिल बुमर्गनर का जवाब देखें: stackoverflow.com/questions/3378696/iphone-try-end-try/… । वह जानता है कि वह किस बारे में बात कर रहा है (संकेत: अपने नियोक्ता की जांच करें)। कोको में अपवाद को अपरिवर्तनीय त्रुटियों के रूप में माना जाता है, और सिस्टम को अस्थिर स्थिति में छोड़ सकता है। NSError सामान्य त्रुटियों को चारों ओर से गुजरने का रास्ता है।
ब्रैड लार्सन

अपवाद हैं असाधारण । व्यावसायिक नियम की विफलता निश्चित रूप से योग्य नहीं है। "अपवाद-भारी कोड को खोजने और डिजाइन करने के परिणामस्वरूप एक सभ्य पूर्ण जीत हो सकती है।" MSDN कोडिंगहोर के
जोनाथन Watmough

3
अपवाद ब्लॉक से नहीं फेंके जा सकते। ARC वातावरण में फेंके गए अपवाद आपके प्रोग्राम को लीक कर सकते हैं। इस प्रकार डाउनवोट।
मोजिजी

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