2017-02-09 9 views
4

Objective-Cカテゴリでこの興味深いコードを見つけました。これはNSExceptionsを捕捉してNSErrorsとしてSwiftコードに渡すために使用されます。Objective-C try-catch - これはなぜコンパイルされますか?そして、なぜビルドとビルドの違いは違うのですか?

私はそれについて理解できません: 1)それはなぜコンパイルされますか?例外がスローされた場合、戻り値はありません。 2)デバッグ(最適化レベルなし)およびリリース(最適化レベル最小/最高速)でコンパイルすると戻り値が異なるのはなぜですか?

機能を呼び出す
- (BOOL)catchException:(void(^)())tryBlock error:(__autoreleasing NSError **)error { 
    @try { 
     tryBlock(); 
     return YES; 
    } 
    @catch (NSException *exception) { 
     NSMutableDictionary *userInfo = [exception.userInfo mutableCopy]; 
     if (!userInfo) userInfo = [NSMutableDictionary new]; 
     userInfo[NSLocalizedDescriptionKey] = exception.reason; 
     *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:userInfo]; 
    } 
    // Note the missing return value outside the try-catch 
} 

NSError *error; 
BOOL result = [self catchException:^{ 
    @throw [NSException exceptionWithName:@"Exception" reason:@"WTF?" userInfo:nil]; 
} error:&error]; 

NSLog(@"Result: %@", result ? @"YES" : @"NO"); 

コンパイルとデバッグ手法を実行している場合、我々が得る:

2017-02-09 10:01:39.695 Compile Test[23129:630118] Result: NO 

、リリーススキームと同じことをやって:

2017-02-09 10:01:39.695 Compile Test[23129:630118] Result: YES 

したがって、try-catchブロックの外側に戻り値がなくてもtry-catch内の戻り値に到達しない場合でも、どちらの場合も戻り値があるようです。私たちはここですべて非常に混乱していますか?

+0

Appleにバグレポートを提出しました。これ以上の問題があります。 –

+0

バグを登録していただきありがとうございます! – bbum

答えて

3

これはコンパイラのバグ、または「戻り値が存在することを確認する制御フローのチェック」オプションがオフの場合(存在する場合)です。

異なる戻り値は、動作が定義されていないためです。

基本的には、レジスタにある可能性があるレジスタは、スタック上にある可能性があります。ターゲットCPUのABIに依存します。関数が返す時の戻り値を保持します。

最適化を行わないと、コンパイラはレジスタとスタックを再利用しません。すべての変数はそれ自身のスペースを取得し、関数の最後に保存されます。最適化を行うと、コンパイラはメモリを積極的に再利用し、動作を変更します。これはまた、最適化されたコードのデバッグがそのような苦痛である理由です。 'myVariable'がリサイクルされたため、 'p myVariable'は予期しない何かを印刷することがあります。

+0

ありがとうございます。これは、定義されていない戻り値の難点を明確に説明しています。私はまだこれをコンパイルするのは困惑しています。コンパイラは、 'return ...'ステートメントが '@try {...}'領域の外側に存在することを要求すると仮定しました。この場合、戻り値の型が何であるかは重要ではないようですが、コンパイラは代わりの戻り値が指定されていないことに気にしません。しかし、あなたの説明は、最終的に返されるものに関しては絶対に意味があります –

関連する問題