実際、NSAssertのポイントは何ですか?


155

なぜなら、私が認識しているのは、アサーションが失敗するとアプリがクラッシュするということだけです。それがNSAssertを使用する理由ですか?それとも他に何の利点がありますか?そして、NSAssertをコードで私が想定する仮定のすぐ上に置くのは正しいことです。たとえば、パラメーターとして-1を受け取ってはならないが、-0.9または-1.1の可能性がある関数のようなものでしょうか。

回答:


300

アサートとは、値が想定どおりであることを確認することです。アサーションが失敗した場合は、何か問題が発生したためにアプリが終了します。アサートを使用する1つの理由は、渡されたパラメーターの1つが正確に特定の値(または値の範囲)でない場合に動作しないか、非常に悪い副作用を引き起こす関数がある場合、アサートを作成することができますその値が期待どおりであることを確認してください。そうでない場合は、何かが本当に間違っているため、アプリが終了します。アサートは、デバッグ/ユニットテストに非常に役立ちます。また、フレームワークを提供して、ユーザーが「悪質な」ことをするのを防ぐフレームワークを提供する場合にも役立ちます。


9
NSAssertをリリースする必要があります。それを行うためのコンパイル時フラグがあります。
バリーウォーク

127
> NSAssertをリリース用に取り出す必要があります。これは議論の余地があります。私は常にアサーションを有効にしてアプリケーションをリリースします。これは多くのソフトウェアの標準的な方法です。たとえば、Appleはこれを行います。プログラムが異常な状態を検出したらすぐにクラッシュするはずです。エラーが発生した場所のスタックトレースを取得できますが、アサートを無効にすると、メモリやユーザーデータが破損する可能性があり、問題のデバッグが非常に困難になります。
マイクウェラー

18
XCode 4のリリース構成では、デフォルトでNS_BLOCK_ASSERTIONSが定義されていることに注意してください。リリースされたコードにNSAssert:sが含まれないことを変更しない場合、私は推測します。
ジョニー

16
私が正しく理解している場合、それらを(リリースバージョンで)残す理由は何ですか?NSAssertをifステートメントに置き換えて、if(何かひどいことが起こった)場合は、ユーザーに通知(または制御下にあること実行)し、単に終了/クラッシュして、何が起こったのかユーザーに知らせないでください ...または私は何かを逃していますか?
Gik

11
通常の状況ではまったく発生しないはずのすべての例外的なケースの道を進むのは、開発者の時間の浪費です。これには、ユーザーごとにユーザーに通知する適切な方法を考えたり、発生後に予期した方法で実行できるようにアプリを堅牢にすることも含まれます。より実用的なアプローチは、アプリをクラッシュさせ、クラッシュレポートから見つかったバグを修正して、新しいバージョンをリリースすることです。そうは言っても、そのような状況でデータの損失がないことを確認することが重要です。それにもかかわらず、これは保証されなければなりませんが、それははるかに少ない仕事です。
trss 2013年

20

NSAssertは実際には話せませんが、Cのassert()と同様に機能すると思います。

assert()は、コードでセマンティックコントラクトを強制するために使用されます。それはどういう意味ですか、あなたは尋ねますか?

まあ、それはあなたが言ったようなものです:-1を受け取るべきではない関数がある場合、assert()でそれを強制することができます:

void gimme_positive_ints(int i){
  assert(i> 0);
}

そして今、あなたはこのような何かをエラーログ(またはSTDERR)に見るでしょう:

アサーションi> 0が失敗しました:ファイルexample.c、2行目

そのため、潜在的に悪い入力から保護するだけでなく、有用な標準的な方法でそれらを記録します。

ああ、少なくともCではassert()はマクロだったので、リリースコードでassert()を何もしないものとして再定義できました。それがNSAssert(またはassert())に当てはまるかどうかはわかりませんが、これらのチェックをコンパイルすることはかなり役に立ちました。


2
はい、NSAssertもマクロです。
Martin Wickman

18

NSAssertアプリをクラッシュさせるだけではありません。クラス、メソッド、およびアサーションが発生した行がわかります。すべてのアサーションは、NS_BLOCK_ASSERTIONSを使用して簡単に非アクティブ化することもできます。したがって、デバッグに適しています。一方、投げるNSExceptionだけでアプリがクラッシュします。また、例外の場所についても通知されず、単純に無効にすることもできません。下の画像の違いをご覧ください。

NSAssertのドキュメントに記載されているように、アサーションでも例外が発生するため、アプリがクラッシュします。

アサーションハンドラーが呼び出されると、メソッド名とクラス名(または関数名)を含むエラーメッセージが出力されます。次に、NSInternalInconsistencyException例外が発生します。

NSAssert:

アサーション後のログ

NSException:

例外後のログ


アンはNSExceptionそれを経由して返す出力をカスタマイズする機会をたくさん提供reasonしてuserInfoパラメータを。クラス名、セレクター、行情報、およびデバッグを支援するために追加したいものを追加できなかった理由はありません。私見、あなたはNSAssert開発中にデバッグ目的で使用しますが、出荷するためにそれらを無効にします。NSException出荷コードのアサーションに残したい場合は、スローします。
markeissler、2015

17

上記の誰もが言ったこととは別に、NSAssert()(Cとは異なりassert())のデフォルトの動作は例外をスローすることで、これをキャッチして処理することができます。たとえば、Xcodeはこれを行います。


例外をキャッチして処理する方法についてはまだありますか?
Gon

1
ココアの例外は事実上「キャッチおよび処理可能」ではありません。呼び出しツリーのどこかで制御がapple関数を通過する場合、動作は未定義です。例外は純粋にエラー報告(別名、クリッターシズムなど)のためのものであり、Javaのような一般的な用途のためのものではありません。
Michael

9

明確にするために、誰かが言及したが完全には説明されていないように、カスタムコードを作成するだけでなくアサートを使用する理由(たとえばifsを実行し、不良データに対して例外を発生させる)は、本番アプリケーションではアサートを無効にする必要がある(SHOULD)ことです。

開発およびデバッグ中に、エラーをキャッチするためにアサートが有効になります。アサートがfalseと評価されると、プログラムは停止します。ただし、本番用にコンパイルする場合、コンパイラーはアサーションコードを省略し、実際にプログラムの実行を高速化します。それまでに、うまくいけば、すべてのバグが修正されました。プロダクション中にプログラムにまだバグがある場合(アサーションが無効でプログラムがアサーションを「スキップ」する場合)、プログラムはおそらく他の時点でクラッシュすることになります。

NSAssertのヘルプから:「プリプロセッサマクロNS_BLOCK_ASSERTIONSが定義されている場合、アサーションは無効になります。」したがって、マクロを配布ターゲットに配置するだけです[のみ]。


6

NSAssert(およびそれに相当するstdlib assert)は、開発中にプログラミングエラーを検出します。プロダクション(リリース済み)アプリケーションで失敗するアサーションはありません。したがって、正の引数を必要とするメソッドに負の数を決して渡さないと主張するかもしれません。テスト中にアサーションが失敗する場合は、バグがあります。ただし、渡された値がユーザーによって入力された場合、本番環境でのアサーションに依存するのではなく、入力の適切な検証を行う必要があります(無効にするリリースビルドに#defineを設定できます)NSAssert*


2
+1あなたの答えが私にとって最も理にかなっているので!NSAssertを使用することは、リリース後ではなく、開発で使用する場合により意味があります。ユーザーが許可されていない値を入力すると、NSAssertがアプリケーションをクラッシュさせるのではなく、UIエラーが続くはずです。霧が晴れました!
pnizzle 2013

3

アサーションは通常、特定のメソッドまたはロジックの一部の使用目的を強制するために使用されます。ゼロより大きい2つの整数の合計を計算するメソッドを書いていたとしましょう。メソッドが常に意図したとおりに使用されていることを確認するために、おそらくその条件をテストするアサートを配置します。

短い答え:彼らはあなたのコードが意図されたようにのみ使用されることを強制します。


3

ランタイムチェックのほかに、アサートプログラミングは、契約に基づいてコードを設計するときに使用される重要な機能であることを指摘しておくことは価値があります。

アサーションおよび契約による設計の詳細については、以下を参照してください。

アサーション(ソフトウェア開発)

契約による設計

アサーションを使用したプログラミング

契約による設計、例による[ペーパーバック]


2

彼の質問に完全に答えるために、あらゆるタイプのアサートのポイントはデバッグを支援することです。ソースでエラーをキャッチし、クラッシュの原因となったときにデバッガーでエラーをキャッチする方が価値があります。

たとえば、関数に値を渡す場合、特定の範囲の値が必要です。関数は、後で使用するために値を保存し、後で使用するとアプリケーションがクラッシュします。このシナリオで見られる呼び出しスタックは、不正な値の原因を示していません。誰が悪い値を渡しているのか、なぜそうなのかを知るために、悪い値をキャッチする方が良いでしょう。


-3

NSAssert条件と一致したときにアプリをクラッシュさせます。条件と一致しない場合、次のステートメントが実行されます。以下のEXを探します。

私はただのタスクをテストするアプリを作成しますNSAssert

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testingFunction:2];
}

-(void)testingFunction: (int)anNum{
    // if anNum < 2 -> the app will crash
    // and the NSLog statement will not execute
    // that mean you cannot see the string: "This statement will execute when anNum < 2"
    // into the log console window of Xcode
    NSAssert(anNum >= 2, @"number you enter less than 2");
    // If anNum >= 2 -> the app will not crash and the below 
    // statement will execute
    NSLog(@"This statement will execute when anNum < 2");
}

私のコードにアプリがクラッシュすることはありません。テストケースは次のとおりです。

  • anNum > = 2->アプリはクラッシュせず、ログ文字列が表示されます。 "このステートメントは、anNum <2"のときにoutPutログコンソールウィンドウに実行されます
  • anNum <2->アプリがクラッシュし、ログ文字列が表示されない: "このステートメントはanNum <2のときに実行されます"

1
あなたはそれを逆に持っています。「NSAssertは、条件と一致するとアプリをクラッシュさせます。条件と一致しない場合、次のステートメントが実行されます。」NSAssertは、条件に一致しない場合にアプリをクラッシュさせ、条件に一致する場合に通常どおり実行します。
Joe Tam、

条件を満たさない場合、アプリがクラッシュし、メッセージをログに記録します。それ以外の場合は、さらに実行されます。
Pravin S.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.