objective c - उद्देश्य-सी/कोको में अपवाद फेंकना




objective-c cocoa (9)

उद्देश्य-सी / कोको में अपवाद फेंकने का सबसे अच्छा तरीका क्या है?


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

@throw[NSException exceptionWithName];

या दूसरी विधि

NSException e;
[e raise];

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


चूंकि ओबीजेसी 2.0, ऑब्जेक्टिव-सी अपवाद अब सी के सेटजेम्प () longjmp () के लिए एक रैपर नहीं हैं, और सी ++ अपवाद के साथ संगत हैं, @ ट्री "नि: शुल्क" है, लेकिन अपवाद फेंकने और पकड़ने का तरीका अधिक महंगा है।

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


मामले के लिए नमूना कोड: @ थ्रो ([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

}

}


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

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

आरआईई


मेरे पास eJames की प्रतिक्रिया पर टिप्पणी करने का प्रतिनिधि नहीं है, इसलिए मुझे लगता है कि मुझे अपना यहां रखना होगा। जावा पृष्ठभूमि से आने वाले लोगों के लिए, आपको याद होगा कि जावा अपवाद और रनटाइम अपवाद के बीच अंतर करता है। अपवाद एक चेक अपवाद है, और रनटाइम अपवाद अनचेक किया गया है। विशेष रूप से, जावा "सामान्य त्रुटि स्थितियों" के लिए चेक अपवादों का उपयोग करता है और "प्रोग्रामर त्रुटि के कारण रनटाइम त्रुटियों" के लिए अनचेक अपवादों का सुझाव देता है। ऐसा लगता है कि उद्देश्य-सी अपवादों का उपयोग उसी स्थान पर किया जाना चाहिए जहां आप एक अनचेक अपवाद का उपयोग करेंगे, और त्रुटि कोड रिटर्न मान या एनएसईआरआरआर मान उन स्थानों पर प्राथमिकता दी जाती है जहां आप चेक अपवाद का उपयोग करेंगे।


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

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

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

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


अपवादों के बजाय असफलताओं को संवाद करने के लिए एनएसईआरआरआर का प्रयोग करें।

एनएसईआरआर के बारे में त्वरित अंक:

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

  • एनएसईआरआरआर को ऑब्जेक्ट होने का लाभ भी है और त्रुटि को अपने उपयोगकर्ता इन्फ्लो डिक्शनरी सदस्य के साथ अधिक विस्तार से वर्णन करने का एक तरीका प्रदान करता है।

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

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


@throw([NSException exceptionWith…])






cocoa