[iOS] NSErrorでエラーハンドリングしたい

2013/06/6

この記事はObjective-C版の記事です。swift2版の記事を書きました
>> [iOS] swift2でもエラーハンドリングしたい NSError, do catch

ここから元記事です
==========================================

こんにちは。きんくまです。
今回はエラーと例外について知りたかったので調べてみました。

まず、こちらのページに書いてありました。

>> Cocoaのプログラミングスタイル

引用してあるAppleのドキュメントからこんな感じにまとめられるかと。

エラー NSError 例外 NSException
ユーザーに関係するエラー。実行時におきる。
例えば、文字の入力に関してだとか、ネットワークの状況だとか。
プログラマーに関係するエラー。
配列のインデックスを範囲外にしてしまったり、メソッドの引数の数を間違えてしまったりとか。
アプリを出荷前になんとかしておく必要がある。

なので、エラーと例外は明確に区別する必要があるそうです。

というわけで、エラーのドキュメントをざっくり読んでみる。

> Introduction to Error Handling Programming Guide For Cocoa

エラーに設定するのは主に3つ

1) ドメイン
2) エラーコード
3) UserInfoのDictionary

1) ドメインは com.company.framework_or_app.ErrorDomain の形にする文字列
カテゴリ分けみたいなものだと思う。同じエラーコードでもドメインが違えば違うエラーと認識できる。

2) エラーコードは NSIntegerで定義

3) UserInfoのDictionary
ここに、エラーの概要、復旧方法を書いておく。
初期設定でDictionaryのkeyがいくつか定義されている。

最低必要そうなのをあげてみる。
・NSLocalizedDescriptionKey(概要)
・NSLocalizedRecoverySuggestionErrorKey(復旧方法)

エラーオブジェクトを作ってあげたあとは、どうやってそれを渡してあげるか考えます。
いろんな方法があると思うのですが、

1) Delegateパターンを使って、NSErrorを引数にするメソッドから渡す方法
2) 関数そのものにNSErrorのポインタのポインタを渡してあげて、エラーがあったらそこに入れてあげる方法

というのがあります。どちらもCocoaではよく使ってますね。

で、以上のものをふまえてサンプルを作ってみました。

今回は、0で数を割ろうとすると、エラーを出すクラスです。

KKFloatDivider.h

#import <Foundation/Foundation.h>

FOUNDATION_EXPORT NSString *const KKFloatDividerErrorDomain;

typedef enum : NSInteger{
    KKFloatDividerErrorZeroDivide
}KKFloatDividerErrorCode;

@interface KKFloatDivider : NSObject
- (CGFloat)divideFloatA:(CGFloat)floatA byFloatB:(CGFloat)floatB error:(NSError **)anError;
@end

KKFloatDivider.m

#import "KKFloatDivider.h"

NSString *const KKFloatDividerErrorDomain = @"com.kumade.handleErrorSample.KKFloatDividerErrorDomain";

@implementation KKFloatDivider
- (CGFloat)divideFloatA:(CGFloat)floatA byFloatB:(CGFloat)floatB error:(NSError **)anError
{
    if(floatB == 0){
        if(anError != NULL){
            NSDictionary *errorDic = @{
                                       NSLocalizedDescriptionKey:@"Number cannot be divided by zero.",
                                       NSLocalizedRecoverySuggestionErrorKey:@"You can set numberB except zero"
                                       };
            *anError = [[NSError alloc] initWithDomain:KKFloatDividerErrorDomain code:KKFloatDividerErrorZeroDivide userInfo:errorDic];
        }
        return CGFLOAT_MAX;
    }
    return floatA / floatB;
}
@end

実際に別のオブジェクトから使ってみます。

- (IBAction)buttonTapped:(id)sender
{
    CGFloat floatA = 5.3;
    CGFloat flaotB = 0;
    
    KKFloatDivider *divider = [[KKFloatDivider alloc] init];
    NSError *error = nil;
    CGFloat result = [divider divideFloatA:floatA byFloatB:flaotB error:&error];
    if(error){
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:error.localizedDescription message:error.localizedRecoverySuggestion delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        return;
    }
    NSLog(@"floatA / floatB = %f", result);
}

今回は、エラーオブジェクトのUserInfoから取り出した概要、復旧方法を使ってUIAlertViewを作りました。

error_handling

これでエラー処理になんとか対処できそうです。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る