objektif-k / kakaoya istisna atmak


Yanıtlar:


528

[NSException raise:format:]Aşağıdaki gibi kullanıyorum :

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

9
Bu @throw([NSException exceptionWith…])yaklaşımı daha kısa ve öz olduğu için tercih ediyorum .
Sam Soffes

9
Önemli uyarıyı zararlardan okuduğunuzdan emin olun ( stackoverflow.com/questions/324284/324805#324805 )
e.James

26
Ben de bunu genel olarak tercih ederim, ama bir tane var. Xcode'un şu anki sürümüm olabilir, ancak [NSException zam ...] sözdizimi ayrıştırıcı tarafından bir değer döndüren bir yöntemden çıkış yolu olarak tanınmıyor gibi görünüyor. Bu sözdizimini kullanırken "Denetim geçersiz olmayan işlevin sonuna ulaşabilir" uyarısını görüyorum, ancak @throw ([NSException exceptionWith…]) sözdizimi ile ayrıştırıcı bunu bir çıkış olarak tanır ve uyarıyı görüntülemez.
mattorb

1
@mpstx Atma sözdizimini her zaman verdiğiniz nedenden dolayı kullanıyorum (ki bu hala iki yıl sonra Xcode 4.6'da geçerli ve muhtemelen her zaman olacak). Uyarılardan kaçınmak istiyorsanız, IDE'nin istisna atmanın bir işlev çıkış noktası olduğunu tanımasını sağlamak sıklıkla önemlidir.
Mark Amery

FWIW @ try / @ catch bloklarının da "kontrol geçersiz olmayan fonksiyonun sonuna ulaşır" uyarıları için yanlış negatif sonuç verdiğini görüyorum (yani uyarı, olması gerektiği zaman görüntülenmiyor)
Brian Gerstle

256

Burada bir uyarı. Objective-C'de, benzer birçok dilden farklı olarak, genellikle normal çalışmada meydana gelebilecek yaygın hata durumları için istisnalar kullanmaktan kaçınmalısınız.

Apple'ın Obj-C 2.0 dokümanları aşağıdakileri belirtir: "Önemli: Objective-C'de istisnalar yoğun kaynak gerektirir. Genel akış denetimi için istisnaları kullanmamalı veya sadece hataları belirtmek için (dosyaya erişilemiyor gibi)"

Apple'ın kavramsal İstisna işleme belgeleri aynı şeyi ancak daha fazla kelime ile açıklıyor: "Önemli: Programlama veya sınır dışı koleksiyon erişimi, beklenmeyen nesneleri değiştirme girişimleri, geçersiz bir mesaj gönderme gibi beklenmedik çalışma zamanı hataları için istisnaların kullanımını ayırmalısınız. Çalışma zamanında değil, bir uygulama oluşturulurken genellikle bu tür hatalarla ilgilenirsiniz. [.....] İstisnalar yerine hata nesneleri (NSError) ve Kakao hata dağıtım mekanizması, Kakao uygulamalarında beklenen hataları iletmenin önerilen yoludur. "

Bunun nedenleri kısmen Objective-C'deki programlama deyimlerine uymaktır (daha basit durumlarda dönüş değerlerini ve daha karmaşık durumlarda referans değer parametrelerini (genellikle NSError sınıfı) kullanmak), kısmen istisnaları atmak ve yakalamak çok daha pahalıdır ve Son olarak (ve en önemlisi), Objective-C istisnalarının C'nin setjmp () ve longjmp () işlevleri etrafında, esasen dikkatli bellek işleminizi bozan ince bir paket olduğu, bu açıklamaya bakın .


11
Bunun çoğu programlama dili için geçerli olduğunu düşünüyorum: "yaygın hata durumları için istisnalar kullanmaktan kaçının". Aynısı Java için de geçerlidir; istisnalar dışında kullanıcı giriş hatalarını (örneğin) ele almak kötü bir uygulamadır. Sadece kaynak kullanımı nedeniyle değil, aynı zamanda kod netliği için.
beetstra

6
Daha da önemlisi, Kakao'daki İstisnalar kurtarılamayan program hatalarını gösterecek şekilde tasarlanmıştır. Aksi takdirde çerçeveye aykırı davranır ve tanımlanmamış davranışa yol açabilir. Ayrıntılar için stackoverflow.com/questions/3378696/iphone-try-end-try/… adresine bakın.
KPM

9
"Aynısı Java için de geçerlidir;" Katılmıyorum. Java'da işaretli istisnaları normal hata koşulları için kullanabilirsiniz. Elbette Çalışma Zamanı istisnalarını kullanmazsınız.
Daniel Ryan

Kakao yolunu tercih ederim (istisnalar sadece programcı hataları içindir) bu yüzden Java'da da yapmayı tercih ederim , ancak gerçek şu ki, bir ortamda tipik uygulamalarla gitmelisiniz ve hata işleme istisnaları bir Objective-C kötü koku, ama Java bu amaç için çok kullanılır.
gnasher729

1
Bu yorum soruyu cevaplamıyor. Belki de OP sadece kilitlenme raporu çerçevesinin beklendiği gibi çalışıp çalışmadığını test etmek için uygulamayı kilitlemek istiyor.
Simon

62
@throw([NSException exceptionWith…])

Xcode, @throwifadeleri, ifadeler gibi işlev çıkış noktaları olarak tanır return. @throwSözdizimini kullanmak, alabileceğiniz " Denetim geçersiz işlevlerin sonuna erişebilir " uyarılarını önler [NSException raise:…].

Ayrıca, @throwsınıf NSException olmayan nesneleri atmak için kullanılabilir.


11
@Steph Thirion: Tüm ayrıntılar için developer.apple.com/documentation/Cocoa/Conceptual/Exceptions/… adresine bakın . Sonuç olarak? Her ikisi de çalışır, ancak @throw, sınıf NSException olmayan nesneleri atmak için kullanılabilir.
e.James

33

İlgili [NSException raise:format:]. Java arka planından gelenler için Java'nın Exception ve RuntimeException arasında ayrım yaptığını hatırlayacaksınız. İstisna, işaretli bir istisnadır ve RuntimeException'ın işareti kaldırılmıştır. Özellikle, Java "normal hata koşulları" için işaretli özel durumlar ve "bir programcı hatasının neden olduğu çalışma zamanı hataları" için işaretlenmeyen özel durumlar kullanmanızı önerir. Objective-C istisnaları, denetlenmeyen bir istisna kullandığınız yerlerde kullanılmalıdır ve kontrol edilen bir istisna kullanacağınız yerlerde hata kodu dönüş değerleri veya NSError değerleri tercih edilir.


1
Evet bu doğrudur (4 yıl sonra: D), NSError sınıfından uzanan kendi hata sınıfınızı ABCError oluşturun ve NSExceptions yerine işaretli özel durumlar için kullanın. Programcı hatalarının (sayı biçimi sorunu gibi beklenmedik bir durum) oluştuğu NSExceptions'ı yükseltin.
chathuram

15

Ben tutarlı olmak için @ throw NSException genişleten kendi sınıfınızla kullanmak daha güzel olduğunu düşünüyorum. Sonra nihayet try catch için aynı notasyonları kullanın:

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

Apple burada istisnaların nasıl atılacağını ve ele alınacağını açıklıyor: İstisnaları Yakalama İstisnaları Atma


hala denemek blok çalışma zamanı istisnası tarafından
çöktü var

14

ObjC 2.0 olduğundan, Objective-C istisnaları artık C'nin setjmp () longjmp () için bir sarıcı değildir ve C ++ istisnası ile uyumludur, @try "ücretsiz" dir, ancak istisnaları atmak ve yakalamak çok daha pahalıdır.

Her neyse, iddialar (NSAssert ve NSCAssert makro ailesini kullanarak) NSException kurar ve bunları Ries devletleri olarak kullanmak aklı başındadır.


Bunu bildiğim iyi oldu! En küçük hatalar için bile istisnalar getiren, değiştirmek istemediğimiz bir üçüncü taraf kütüphanemiz var. Onları uygulamada tek bir yerde yakalamak zorundayız ve sadece bizi rahatsız ediyor, ama bu beni biraz daha iyi hissettiriyor.
Yuri Brigance

8

İstisnalar yerine hataları iletmek için NSError kullanın.

NSError hakkında hızlı noktalar:

  • NSError, C stili hata kodlarının (tamsayılar) kök nedenini açıkça tanımlamasına ve umarım hata işleyicisinin hatayı aşmasına izin verir. Hata kodlarını SQLE gibi C kitaplıklarından NSError örneklerinde çok kolay bir şekilde sarabilirsiniz.

  • NSError ayrıca bir nesne olma avantajına sahiptir ve hatayı userInfo sözlük üyesi ile daha ayrıntılı olarak açıklamanın bir yolunu sunar.

  • Ama hepsinden önemlisi, NSError AÇILAMAZ; bu nedenle, sıcak patatesi daha da ileriye taşıyan ve yalnızca kullanıcıya bildirilebileceği çağrı yığınını daha ileriye taşıyan diğer dillerden farklı olarak, hata işlemeye daha proaktif bir yaklaşımı teşvik eder. anlamlı bir şekilde ele alınmaz (eğer OOP'un en büyük bilgi gizleme ilkesini takip etmeye inanıyorsanız değil).

Referans Linki: Referans


Bu yorum soruyu cevaplamıyor. Belki de OP sadece kilitlenme raporu çerçevesinin beklendiği gibi çalışıp çalışmadığını test etmek için uygulamayı kilitlemek istiyor.
Simon

7

Ben "Big Nerd Ranch Kılavuzu (4. baskı)" dan nasıl öğrendim:

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

Tamam, ama hakkında pek bir şey söylemiyor userInfo:nil. :)
Decur

6

Try catch bloğunda istisna oluşturmak için iki yöntem kullanabilirsiniz

@throw[NSException exceptionWithName];

veya ikinci yöntem

NSException e;
[e raise];

3

Normal program akışını kontrol etmek için Asla Özel Durumlar'ı asla kullanmamanız gerektiğine inanıyorum. Ancak, bir değer istenen değerle eşleşmediğinde istisnalar atılmalıdır.

Örneğin, bazı işlev bir değeri kabul ederse ve bu değerin hiçbir zaman sıfır olmasına izin verilmiyorsa, 'akıllı' bir şey yapmaya çalışmak yerine bir istisna atmak iyidir ...

Ries


0

İstisnaları yalnızca kendinizi bir programlama hatasını gösteren bir durumda bulursanız ve uygulamanın çalışmasını durdurmak istiyorsanız atmalısınız. Bu nedenle, özel durumları atmanın en iyi yolu NSAssert ve NSParameterAssert makrolarını kullanmak ve NS_BLOCK_ASSERTIONS öğesinin tanımlanmadığından emin olmaktır.


0

Vaka için örnek kod: @throw ([NSException istisnası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);
}

}

Kullanımı:

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

Başka bir daha gelişmiş kullanım örneği:

- (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

İş kuralı istisnalarını belirtmek için bile, istisna C'yi normalde objektif C'de kullanmamak için hiçbir neden yoktur. Apple umurunda NSError kullanın diyebiliriz. Obj C uzun zamandır var ve bir zamanlar ALL C ++ belgeleri aynı şeyi söyledi. İstisna atmanın ve yakalamanın ne kadar pahalı olduğu önemli değil, bir istisnanın ömrü son derece kısadır ve ... normal akışa bir istisnadır. Hayatımda hiç kimsenin söylediğini hiç duymadım, bu istisnanın atılması ve yakalanması uzun sürdü.

Ayrıca, amaç C'nin çok pahalı olduğunu ve bunun yerine C veya C ++ 'da kodladığını düşünen insanlar var. Yani her zaman NSError kullan demek bilgisiz ve paranoyaktır.

Ancak bu konunun sorusu henüz bir istisna atmanın en iyi yolu ne cevaplanmadı. NSError'a geri dönmenin yolları açıktır.

Öyleyse: [NSException zam: ... @throw [[NSException ayır] initWithName .... veya @throw [[MyCustomException ...?

Burada işaretli / işaretsiz kuralı yukarıdakinden biraz farklı kullanıyorum.

Kontrol edilen / işaretlenmeyen (burada java metaforunu kullanarak) arasındaki gerçek fark önemlidir. Ve kurtarma ile sadece çarpışma DEĞİL demek değil.

Bu nedenle, kurtarılabilir istisnalar için @throw ile özel istisna sınıfları kullanıyorum, çünkü büyük olasılıkla birden fazla @catch bloğunda belirli hata türlerini arayan bazı uygulama yöntemlerine sahip olacağım. Örneğin, uygulamam bir ATM makinesi ise, "WithdrawalRequestExceedBalanceException" için bir @catch bloğum olurdu.

NSException: çalışma zamanı özel durumları için zamını kullanıyorum, çünkü daha yüksek düzeyde yakalamak ve günlüğe kaydetme dışında, istisnadan kurtulmanın hiçbir yolu yoktur. Ve bunun için özel bir sınıf yaratmanın bir anlamı yok.

Her neyse, yaptığım şey bu, ama daha iyi, benzer şekilde etkileyici bir yol varsa ben de bilmek istiyorum. Kendi kodumda, C kodunu uzun zaman önce durdurduğumdan beri, bir API tarafından geçirilmiş olsam bile bir NSError döndürmüyorum.


4
"Normalde amaç C'de istisnaları kullanmamak için hiçbir neden yok" gibi genelleme ifadeleri yapmadan önce hata durumlarının normal akışının bir parçası olarak istisnalar olan bir sunucu programlamaya çalışmanızı tavsiye ederim. İster inanın ister inanmayın, ObjC'de yüksek performanslı uygulamalar (veya uygulamaların en azından bir kısmı) yazmak ve istisnalar atmak normalde performansı ciddi şekilde engeller.
jbenet

6
Gerçekten de Kakao'da istisnaları kullanmamanın çok iyi nedenleri var. Daha fazla bilgi için Bill Bumgarner'ın cevabına bakınız: stackoverflow.com/questions/3378696/iphone-try-end-try/… . Ne hakkında konuştuğunu biliyor (ipucu: işvereni kontrol et). Kakao istisnaları kurtarılamaz hatalar olarak kabul edilir ve sistemi dengesiz bir durumda bırakabilir. NSError, genel hataları aşmanın yoludur.
Brad Larson

İstisnalar istisnadır . İş kuralı başarısızlıkları kesinlikle yeterli değildir. "İstisna-ağır kod bulmak ve tasarlamak iyi bir kazanç sağlar." MSDN üzerinden codinghorror.com/blog/2004/10/…
Jonathan Watmough

3
Bloklardan istisnalar atılamaz. ARC ortamında atılan istisnalar programınızı sızdırabilir. Böylece aşağı oy.
Moszi

"Bir istisna atmanın ve yakalamanın ne kadar önemli olduğu önemli değil" Performansın kritik olduğu bir emülatör yazıyorum. Bir sürü pahalı istisna atamam.
NobodyNada
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.