2009-06-26 14 views
8

私はさまざまなルーチンをコーディングしています。私はそれをきちんとしてリファクタリングするよう全力を尽くしています。私が作成していNSErrorを使用してエラーをチェックする正しい構造

方法は、このコードのようになり始めています:

-(IBAction)buttonPress:(id)sender { 
    // Create Document Shopping List with this document 
    [self doSomething:&error]; 

    if(error) { 
     [NSApp presentError:&error]; 
     return nil; 
    } 

    [self doSomethingElse:&error]; 

    if(error) { 
     [NSApp presentError:&error]; 
     return nil; 
    } 

    [self doYetSomethingElse:&error]; 

    if(error) { 
     [NSApp presentError:&error]; 
     return nil; 
    } 
} 

私はNSErrorを愛するが、これは私のすべてのエラーを処理するとても不器用なやり方のように思えます。

私は別の方法について持っていたいくつかの考え:

a)のエラーチェックがメソッドのdoSomething、doSomethingElseなどに組み込むことができ、その後私はせずにボタンを押す方法を終了することができないであろう戻り値について何らかのチェックをして、同様の構造に戻すことができます。

b)NSErrorをKey Value Observedとして設定することができましたが、これについて深刻な問題があると感じています。私はKVOとの虐待の可能性を非常に認識しているので、私は可能な限り無理なくすべてをやろうとしています。

本当にここで基本的なものが欠けていますか?私を助けることができるパターンがありますか?またはこの構造はOKですか?

+0

私は過去10分間に私が受け取った驚くべき反応によって全く変わりました!あなたの答えはどうもありがとう。非常に、非常に有用です。 –

答えて

11

私がここで提示した回答のどれも、アップルの推奨されている方法を考慮していないと思います。

基本的には、NSErrorオブジェクトをチェックして問題がないかどうかを確認しないでください。 NSErrorへのポインタへのポインタを取るメソッドから返された値をチェックすることによって、問題があるかどうかをチェックします。 the Apple documentationから

重要成功または失敗は メソッドの戻り値で示されています。 方法は、直接nilまたはNOを返すことで失敗したことを示している場合、間接的 にエラーオブジェクトを返すココア方法がココアのエラー・ドメインは、そのようなオブジェクトを返すことが保証されている、あなたは 常にnilまたはNO しようとする前に、戻り値があることを確認する必要がありますNSErrorオブジェクトを使用してください。

+0

sendAsynchronousRequestのようないくつかのメソッドはvoidを返します。唯一できることはNSErrorです。または私は何かを逃していますか? –

+2

この場合、他のパラメータをチェックします。つまり、NSURLResponseとNSDataです。 –

0

注:私がこれを投稿したとき、私はMacOS/Cocoaの例外の議論を知らなかった。この答えを考えているときは、このことを覚えておいてください。

代わりにexceptionsを使用しないのはなぜですか?これにより、メソッドのエラーパラメータを省略し、エラーを1か所で処理できます。

-(IBAction)buttonPress:(id)sender { 
    // Create Document Shopping List with this document 
    @try { 
     [self doSomething]; 
     [self doSomethingElse]; 
     [self doYetSomethingElse]; 
    } @catch (NSException* e) { 
     [NSApp presentException:e]; 
    } 
    return nil; 
} 

もちろん、あなたdoXXXX方法の中から必要に応じて例外をスローする必要があります。

NSException* e = [NSException exceptionWithName:@"MyException" 
             reason:@"Something bad happened" 
             userInfo:nil]; 
@throw e; 
+3

Mac OS X/Cocoaでは、フロー制御に例外を使用することが許容されているかどうかに関して、現在進行中の議論があります。私は個人的には、(ほとんどの)Appleが取っているところでは、Cocoaの例外は例外的なプログラミングエラーであるため、フロー制御には使用しないでください。 – danielpunkass

+0

これがなぜマークされたのか知りたいですか。私は何を逃したのですか? – teabot

+2

ああ、@danielpunkassをクリアしてくれてありがとう - 私はJavaのバックグラウンドだから、Objective-Cの例外を喜んで使っています。 – teabot

1

私は本当の問題は、あなたのエラー処理に必要などのくらいの細かさだと思います。あなたのコードは根本的に正しいですが、頻繁にエラーをチェックしたり、NSExceptionで彼の答えに挙げられているteabotのようなキャッチオールの手法を使って、クリーンアップすることができます。 NSFileManagerのmoveItemAtPath :)のようなエラーを返す組み込み関数の多くは、NSErrorオブジェクトを提供することに加えてBOOLを返すので、NSError情報が必要ない場合は、ネストされたifステートメントを使用することもできます。

しかし、これを行うには本当に素晴らしい方法はありません。あなたのコードが長い場合、KVOはクールな解決策かもしれません。私はこのような状況でそれを試したことはありません。

+0

コメントありがとう、ベン。理想的には、NSErrorを使用することで、一貫した方法ですべてのエラーを処理できるようにしたいと考えています。私は時にはBOOLを返す関数が多少混乱しています - NSErrorを使ってエラーを処理する標準的な方法があれば、なぜAppleも戻り値を提供することによって水を泥まませにするでしょうか?それはいつも私をちょっと混乱させている。 –

+1

NSErrorオブジェクトは、率直に言って愚かです。エラーオブジェクトを作成するためのコードを記述する際に手間がかかり過ぎ、その結果、メソッドが誤って成功を報告してしまうようなエッジケースを見逃すことは非常に簡単です。 これはAppleがエラー情報を処理する理由です。 NOまたはnilを返すメソッドの単純なテストを使用して、失敗したと判断します。それから、NSErrorオブジェクト(使用可能な場合)にドロップして詳細を確認します。 –

+0

非常に良い点、マイク。私に何か他のことを考えさせる。ちょうどこれを読んで、私はすぐに十分に確認してはいけません。 –

2

質問の要点は、エラー処理に構造的な改善があるかどうかです。基本的には、より多くのコードを別々のメソッド/関数に抽出するか、高水準のサンプルメソッドにネストを導入することによって、より多くのネスティングレイヤーを導入することによって、そう考えています。

考えられるのは、ほとんどのエラーを処理する場合は、代替タスクを実行することに関心があるか、エラーの原因となってチェーンを上ってエラーを伝播して、責任あるコントローラがエラーをユーザーに伝えることができますUI。「伝播またはハンドル」のこのアイデアを使用して

、私はこのようなあなたのサンプルメソッドを書き換えます:特定の方法では、あまりにも多くのネスティングを導入に対する良好な引数があることを

-(IBAction)buttonPress:(id)sender { 

    // Create Document Shopping List with this document 
    [self doSomething:&error];  
    if(error == nil) { 
     [self doSomethingElse:&error]; 
     if (error == nil) { 
      [self doYetSomethingElse:&error]; 
     } 
    } 

    if(error) { 
     [NSApp presentError:&error]; 
    }  
} 

注意。このようなネストは、本質的にメソッドを抽出するための短い代替手段です。例えば「doSomething:」自体がdoSomethingElse:を呼び出すという意味で、doYetSomethingElseを呼び出します。これは、if-nestと同じ構造をコードに課しますが、間違いなくより保守性が高いでしょう。

脇に、私はインラインリターンステートメントのファンではありません。この特定の例では、サンプルメソッドは実際に戻り値を呼び出すのではありませんが、そうした場合は、返された値にローカル変数を設定し、フローコントロールの最後でのみ戻ります。関数やメソッドから早期に飛び出すことは、奇妙なバグIMHOに遭遇する確実な方法です。

+0

ダニエルの素晴らしい提案をありがとう。コード・コンプリートはネストを最小化することを推奨しているので、私はこれをやめてしまいました。私はいくつかの悪夢を入れた。そして私が5つ以上のステップを持っていれば、これは面倒になるだろうと思います。 一方、5つ以上のステップがある場合、私のコードをリファクタリングする必要があるという警告サインになると思います。そして、この特定のネスティングはまだかなり読みやすく、私のオリジナルよりもはるかに綺麗ですので、これは私がやることです。 もう一度おねがいします! –

+1

あなたはその答えをうれしく思っています。コードコンプリートとネストを最小限に抑えることも考えていますが、最小ネストは、状況によっては別のメソッドや関数に組み込むことができるコードの省略形にすぎません。 一般的に、入れ子にするのは、代替の「実行」機能よりも優れていると思います... – danielpunkass

関連する問題