こんにちはオリバー、私はこの質問に出くわしたばかりで、答えようと思っていました.
まず、インデックスが厳密にstringLength未満でstringLength == [string length]
あることを確認する必要があると仮定します。つまり、以下ではありません。
for (i=0; i < stringLength; i++) {
unichar currentCharacter = [string characterAtIndex:i];
...}
たとえば、5 文字の文字列には 5 つの有効なインデックスがあります。0、1、2、3、4。
その修正により、例外が発生するのを防ぐ必要がありますが、例外についてさらに説明します (インデックスの off-by-one エラーに気付く前に書いたものです)。
例外は通常の戻り値とは異なり、関数が呼び出し元にエラー状態を通知できる特別な緊急チャネルのようなものであり、エラー状態を通常の戻り値に詰め込む必要はありません。
用語は、例外は「発生」または「スロー」されるほど「返される」わけではないということです (言語によって異なります)。次に、例外が「キャッチ」または「レスキュー」されます (言語によって異なります)。
例外は例外的な状況でのみ使用する必要があり、(入力をサニタイズすることによって) 例外を回避する何らかの方法がある場合は、最初にそれを行う必要があります。可能であれば例外を避けるもう 1 つの理由は、一部の言語では、例外をキャッチするプロセスが非常に効率的でなく、メモリ割り当てが少し不安定になる可能性があることです。
ただし、例外的な状況では、戻り値の範囲でエラー状態を表現する方法を工夫する必要なく、呼び出し元の関数にエラーを通知する便利な方法です。
それでは、実用性に移ります。あなたのケースで例外をキャッチするための構文は次のようになります。
@try {
for (i=0; i <= stringLength; i++) {
unichar currentCharacter = [string characterAtIndex:i];
}
}
@catch (NSException *exception) {
NSLog(@"uh oh..");
// handle the exception here
}
これにより、NSRangeException だけでなく、スローされたすべての例外がキャッチされます。多くの言語では、 のような構文を使用してより選択的にすることができますが@catch (NSRangeException *exception)
、残念ながら、Objective-C ではそうではありません。これは、NSRangeException が NSException のサブクラスとして定義されておらず、代わりに NSException の -name 値に現れる NSString 定数であるためです。Objective-C でより選択的にするには、次のようにする必要があります。
@catch (NSException *exception) {
if ([[exception name] isEqualToString:NSRangeException]) {
NSLog("got an NSRangeException");
// handle the exception here
} else {
NSLog("got an exception we can't handle so pass it down the chain");
@throw exception;
}
}
ご覧のとおり、例外をキャッチするのは非常に厄介な場合があるため、常に例外を回避することをお勧めします。このコードが NSRangeException をトリガーする場合、非常に例外的な (そしておそらく制御できない) 何かが発生しているに違いありません。
for (i=0; i < [string length]; i++) {
unichar currentCharacter = [string characterAtIndex:i];
...}