Objective-C try-catch - 为什么编译?为什么返回不同的构建调试版本?

问题描述:

在Objective-C类中找到了这个有趣的代码,用于捕获NSExceptions并将它们作为NSErrors传递给Swift代码。Objective-C try-catch - 为什么编译?为什么返回不同的构建调试版本?

我不明白的是: 1)为什么它甚至编译?如果抛出异常,则永远不会有返回值。 2)为什么当使用debug(优化级别none)和release(优化级别最小/最快)进行编译时,返回值会有所不同?

- (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

谢谢你提交bug! – bbum

这是一个编译器错误或“检查确保返回值存在的控制流”选项是关闭的(如果有的话)。

不同的返回值是因为行为未定义。

基本上,无论发生什么情况 - 可能是一个寄存器,可能在堆栈上,取决于目标CPU的ABI - 在函数返回时将保留返回值。

没有优化,编译器不会重用寄存器和堆栈;每个变量都有自己的空间,并保存到函数的末尾。通过优化,编译器将主动重用内存,导致行为改变。这也是为什么调试优化代码是如此痛苦的原因; 'myVariable'可能会打印出一些意想不到的东西,因为'myVariable'已被回收。

+0

谢谢。这明确解释了未定义的返回值难题。我仍然对这个编译器感到困惑,我认为编译器应该要求'@try {...}'区域之外存在'return ...'语句。在这种情况下,返回类型似乎并不重要,编译器根本不在意没有指定其他返回值。但是,你的解释对于最终返回的内容是绝对有意义的 –