Objektif-c / kakaoya istisna atmanın en iyi yolu nedir?
Objektif-c / kakaoya istisna atmanın en iyi yolu nedir?
Yanıtlar:
[NSException raise:format:]
Aşağıdaki gibi kullanıyorum :
[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
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 .
@throw([NSException exceptionWith…])
Xcode, @throw
ifadeleri, ifadeler gibi işlev çıkış noktaları olarak tanır return
. @throw
Sözdizimini kullanmak, alabileceğiniz " Denetim geçersiz işlevlerin sonuna erişebilir " uyarılarını önler [NSException raise:…]
.
Ayrıca, @throw
sınıf NSException olmayan nesneleri atmak için kullanılabilir.
İ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.
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
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.
İ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
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
İ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.
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
}
}
İş 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.
@throw([NSException exceptionWith…])
yaklaşımı daha kısa ve öz olduğu için tercih ediyorum .