Objective-Cでのエラー処理

  • 17
    Like
  • 0
    Comment
More than 1 year has passed since last update.

目的

どうやればいいか疑問だったため、まとめるのも兼ねて

基本

エラーに用いるオブジェクトは2つ

  • NSError
  • NSException

それぞれ詳しく見てみると

NSError

一般的なエラーはこれで扱う
プロパティは3つで

  • domain
  • code
  • userInfo

domain -> com.example.applicationのような識別子
code -> そのままエラーのコード
userInfo -> NSDictionaryを想定していて、NSLocalizedDescriptionKeyにエラーメッセージを設定する

使い方としては[NSError errorWithDomain:code:userInfo]を使って生成、
関数の返り値として用いるのが普通

NSException

プログラマのせいで起こるエラー
代表的なのは、不正なインデックスでNSArrayにアクセスした時のNSRangeExceptionなど

正常なApplicationの遷移の中で使用することは推奨されておらず、
リリース版では基本的にExceptionが生成されないようにしなければならない

このために@try @catch @finally構文も存在する

ライブラリ開発するときには、不正な操作に対して飛ばす感じになる?

実際のアプリケーション開発の中でのエラー処理

結論としては、NSErrorの生成、場合分けをラップして使うのがベストな気がするところ

多分こんな感じ

superClass

// Domain
static const NSString ERROR_DOMAIN = @"com.example.app";

@interface MyError
@property(strong, nonatmic)NSError *error;
-(instancetype)initWithCode:(NSInteger)code reason:(NSString *)reason;
-(void)showAlert;
@end

@implementation MyError

-(instancetype)initWithCode:(NSInteger)code reason:(NSString *)reason {
    self = [super init];
    if(!self) return nil;
    NSDictionary *info = @{@"NSLocalizedDescriptionKey": reason};
    _error = [NSError errorWithDomain:ERROR_DOMAIN code:code userInfo:info];
    return self;
}

@end
childClass
@implementation MyNetworkError

+(instancetype)init {
  self = [super initWithCode:100 reason:@"cant reach to server"];
  if(!self) return nil;
  return self;
};

/** 
 * こんなのあると便利かもしれない 
 * 他にもエラー関連の仕事などはこのクラスに実装してしまう
 **/
-(PMKPromise *)showAlert {
  // メッセージ等適当に設定してアラート出す
  // Promiseで押されたインデックス等の情報を返す
}

// こういうのとかも
-(void)log {
  NSLog(@"%@", _error);
}

@end

エラーコードとかベタ書きする実装もなくはないが、
- 際限なし膨らむ (ので見通し悪い
- エラーオブジェクトに仕事させられない
- 判断のifがひたすら増える

等あるのでやはりクラスに局所化しときたいところ
ちなみにこんなやつ

static const NSString *NETWORK_ERROR_DESCRIPTION = @"cant reach server";
// etc...

static const NSString *NETWORK_ERROR_CODE = 100;
// etc...

// を、1ファイルにずらずら書いて、使う際に毎回
// if(error.code == NETWORK_ERROR_CODE) {
//   //ダイアログ出したり
// } else if (error.code == DB_ERROR_CODE) {
//   //無視したり
// }
// を書かないといけないようなそんなような

何かツッコミ等や改善点あれば教えていただけると助かります

最後に

書いてて思ったのは、アプリごとにこれいちいち書くのはめんどくさいので、ライブラリ作っちゃえばいいじゃん!
と思ったが、時代はSwiftなので、Swiftのエラーハンドリングも調べなければという感じ
というかすでにあるかも?という点は要調査

参考

Dealing with Errors 公式
NSError Class Reference 公式
Objective-C事始め – NSErrorの3つのプロパティ