Uygulamamdaki hataları yakalamak için çalışıyorum ve kullanmayı düşünüyorum NSError
. Nasıl kullanılacağı ve nasıl doldurulacağı konusunda biraz kafam karıştı.
Biri nasıl doldurup nasıl kullandığım konusunda bir örnek verebilir NSError
mi?
Uygulamamdaki hataları yakalamak için çalışıyorum ve kullanmayı düşünüyorum NSError
. Nasıl kullanılacağı ve nasıl doldurulacağı konusunda biraz kafam karıştı.
Biri nasıl doldurup nasıl kullandığım konusunda bir örnek verebilir NSError
mi?
Yanıtlar:
Peki, genellikle yaptığım zaman içinde hata-out bir NSError
işaretçi bir referans almak olabilir benim yöntemler var . Bu yöntemde bir şey gerçekten yanlış giderse, NSError
referansı hata verileriyle doldurabilir ve yöntemden sıfır döndürebilirim.
Misal:
- (id) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
*error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
Daha sonra böyle bir yöntemi kullanabiliriz. Yöntem nil döndürmediği sürece hata nesnesini incelemeyi bile zahmet etmeyin:
// initialize NSError object
NSError* error = nil;
// try to feed the world
id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!yayOrNay) {
// inspect error
NSLog(@"%@", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
İçin localizedDescription
bir değer ayarladığımız için hatalara erişebildik NSLocalizedDescriptionKey
.
Daha fazla bilgi için en iyi yer Apple'ın belgeleridir . Gerçekten iyi.
Ayrıca Cocoa Is My Girlfriend hakkında güzel, basit bir öğretici var .
id
a BOOL
. Hafif ARC uyumlu varyasyonlar çok takdir edilecektir.
BOOL
. NO
Hata durumunda geri dönün ve dönüş değerini kontrol etmek yerine kontrol edin error
. Eğer nil
devam edersen , != nil
halledersen.
**error
nil olmadığını doğrulayan bir kod eklemeniz gerekir . Aksi takdirde, program tamamen düşmanca bir hata atar ve ne olduğunu açıkça göstermez.
En son uygulamamı temel alarak daha fazla öneri eklemek istiyorum. Apple'ın bazı kodlarına baktım ve kodumun aynı şekilde davrandığını düşünüyorum.
Yukarıdaki gönderiler zaten NSError nesnelerini nasıl oluşturacağınızı ve onları nasıl geri getireceğinizi açıklıyor, bu yüzden bu bölümle uğraşmayacağım. Sadece kendi uygulamanızdaki hataları (kodlar, mesajlar) entegre etmek için iyi bir yol önermeye çalışacağım.
Alan adınızdaki tüm hatalara (uygulama, kitaplık vb.) Genel bir bakış olacak 1 başlık oluşturmanızı öneririz. Geçerli başlığım şöyle görünüyor:
FSError.h
FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain;
enum {
FSUserNotLoggedInError = 1000,
FSUserLogoutFailedError,
FSProfileParsingFailedError,
FSProfileBadLoginError,
FSFNIDParsingFailedError,
};
FSError.m
#import "FSError.h"
NSString *const FSMyAppErrorDomain = @"com.felis.myapp";
Şimdi yukarıdaki hatalar için değerleri kullanırken, Apple uygulamanız için bazı temel standart hata mesajları oluşturacaktır. Aşağıdaki gibi bir hata oluşturulabilir:
+ (FSProfileInfo *)profileInfoWithData:(NSData *)data error:(NSError **)error
{
FSProfileInfo *profileInfo = [[FSProfileInfo alloc] init];
if (profileInfo)
{
/* ... lots of parsing code here ... */
if (profileInfo.username == nil)
{
*error = [NSError errorWithDomain:FSMyAppErrorDomain code:FSProfileParsingFailedError userInfo:nil];
return nil;
}
}
return profileInfo;
}
error.localizedDescription
Yukarıdaki kod için Apple tarafından oluşturulan standart hata mesajı ( ) aşağıdaki gibi görünecektir:
Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"
Yukarıdaki mesaj, bir geliştirici için zaten oldukça yararlıdır, çünkü mesaj hatanın meydana geldiği alanı ve ilgili hata kodunu görüntüler. Son kullanıcıların hata kodunun ne 1002
anlama geldiğine dair hiçbir fikri olmayacak , bu yüzden şimdi her kod için bazı güzel mesajlar uygulamalıyız.
Hata iletileri için yerelleştirmeyi akılda tutmamız gerekir (yerelleştirilmiş iletileri hemen uygulamasak bile). Mevcut projemde şu yaklaşımı kullandım:
1) strings
hataları içerecek bir dosya oluşturun . Dizeler dosyaları kolayca yerelleştirilebilir. Dosya aşağıdaki gibi görünebilir:
FSError.strings
"1000" = "User not logged in.";
"1001" = "Logout failed.";
"1002" = "Parser failed.";
"1003" = "Incorrect username or password.";
"1004" = "Failed to parse FNID."
2) Tamsayı kodlarını yerelleştirilmiş hata mesajlarına dönüştürmek için makrolar ekleyin. Sabitler + Macros.h dosyamda 2 makro kullandım. MyApp-Prefix.pch
Kolaylık sağlamak için bu dosyayı her zaman önek başlığına ( ) eklerim.
Sabitler + Macros.h
// error handling ...
#define FS_ERROR_KEY(code) [NSString stringWithFormat:@"%d", code]
#define FS_ERROR_LOCALIZED_DESCRIPTION(code) NSLocalizedStringFromTable(FS_ERROR_KEY(code), @"FSError", nil)
3) Artık bir hata koduna dayalı kullanıcı dostu bir hata mesajı göstermek kolaydır. Bir örnek:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code)
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
Constants+Macros.h
ve bu dosyayı önek başlığına ( .pch
dosya) alır, böylece her yerde kullanılabilir. 2 makrodan yalnızca birini kullandığınızı kastediyorsanız, bu işe yarayabilir. Belki dönüşüm int
için NSString
bu test değil de, gerçekten gerekli değildir.
.strings
dosya) olması gerekir , çünkü Apple'ın makrosu burada görünür. NSLocalizedStringFromTable
Burada kullanma hakkında bilgi edinin : developer.apple.com/library/mac/documentation/cocoa/conceptual/…
FS_ERROR_LOCALIZED_DESCRIPTION
Makrodaki kod adlı bir dosyada yerelleştirilebilir dizeyi denetler FSError.strings
. Bu .strings
sizin için yabancıysa, Apple'ın dosyalardaki yerelleştirme kılavuzuna göz atmak isteyebilirsiniz .
Harika cevap Alex. Potansiyel konulardan biri NULL dereference. Apple'ın NSError nesneleri Oluşturma ve İade Etme referansı
...
[details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
...
Lütfen aşağıdaki eğiticiye bakın
umarım sizin için yararlı olacaktır ama önce NSError belgelerini okumak zorundasınız
Bu son zamanlarda bulduğum çok ilginç bir bağlantı ErrorHandling
Alex ve jlmendezbonini'nin büyük cevabını özetlemeye çalışacağım, her şeyi ARC uyumlu hale getirecek bir değişiklik ekleyeceğim (şimdiye kadar ARC şikayet edeceğinizden beri dönmeyecek id
, "herhangi bir nesne" anlamına geliyor, ancak BOOL
bir nesne değil) ) kullanımı önerilir.
- (BOOL) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return NO;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
Şimdi yöntem çağrımızın dönüş değerini kontrol etmek yerine error
, hala olup olmadığını kontrol ediyoruz nil
. Eğer değilse, bir sorunumuz var.
// initialize NSError object
NSError* error = nil;
// try to feed the world
BOOL success = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!success) {
// inspect error
NSLog(@"%@", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
Gördüğüm başka bir tasarım deseni, özellikle bir yöntem eşzamansız olarak çalıştırıldığında yararlı olan blokları kullanmayı içerir.
Aşağıdaki hata kodlarının tanımlandığını varsayalım:
typedef NS_ENUM(NSInteger, MyErrorCodes) {
MyErrorCodesEmptyString = 500,
MyErrorCodesInvalidURL,
MyErrorCodesUnableToReachHost,
};
Aşağıdaki gibi bir hata oluşturabilecek yönteminizi tanımlarsınız:
- (void)getContentsOfURL:(NSString *)path success:(void(^)(NSString *html))success failure:(void(^)(NSError *error))failure {
if (path.length == 0) {
if (failure) {
failure([NSError errorWithDomain:@"com.example" code:MyErrorCodesEmptyString userInfo:nil]);
}
return;
}
NSString *htmlContents = @"";
// Exercise for the reader: get the contents at that URL or raise another error.
if (success) {
success(htmlContents);
}
}
Ve sonra onu çağırdığınızda, NSError nesnesini bildirme (kod tamamlama sizin için yapacak) veya dönen değeri kontrol etme konusunda endişelenmenize gerek yok. Sadece iki blok sağlayabilirsiniz: biri istisna olduğunda çağrılacak, diğeri başarılı olduğunda çağrılacak:
[self getContentsOfURL:@"http://google.com" success:^(NSString *html) {
NSLog(@"Contents: %@", html);
} failure:^(NSError *error) {
NSLog(@"Failed to get contents: %@", error);
if (error.code == MyErrorCodesEmptyString) { // make sure to check the domain too
NSLog(@"You must provide a non-empty string");
}
}];
extension NSError {
static func defaultError() -> NSError {
return NSError(domain: "com.app.error.domain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Something went wrong."])
}
}
NSError.defaultError()
geçerli bir hata nesnesi olmadığında kullanabilirsiniz .
let error = NSError.defaultError()
print(error.localizedDescription) //Something went wrong.