2017-02-09 37 views
4

在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

回答

3

這是一個編譯器錯誤或「檢查確保返回值存在的控制流」選項是關閉的(如果有的話)。

不同的返回值是因爲行爲未定義。

基本上,無論發生什麼情況 - 可能是一個寄存器,可能在堆棧上,取決於目標CPU的ABI - 在函數返回時將保留返回值。

沒有優化,編譯器不會重用寄存器和堆棧;每個變量都有自己的空間,並保存到函數的末尾。通過優化,編譯器將主動重用內存,導致行爲改變。這也是爲什麼調試優化代碼是如此痛苦的原因; 'myVariable'可能會打印出一些意想不到的東西,因爲'myVariable'已被回收。

+0

謝謝。這明確解釋了未定義的返回值難題。我仍然對這個編譯器感到困惑,我認爲編譯器應該要求'@try {...}'區域之外存在'return ...'語句。在這種情況下,返回類型似乎並不重要,編譯器根本不在意沒有指定其他返回值。但是,你的解釋對於最終返回的內容是絕對有意義的 –