你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> Clang 警告:可空值強轉為不可空值

Clang 警告:可空值強轉為不可空值

編輯:IOS開發基礎

1.jpg

  • 本文由CocoaChina譯者星夜暮晨翻譯

  • 原文:CLANG WARN NULLABLE TO NONNULL CONVERSION

Xcode 7 包含了一個名為 “Apple LLVM 7.0 - Warnings - All languages > Incorrect Uses of Nullable Values” 的項目設置選項,其鍵為 CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION

您可以使用 -Wnullable-to-nonnull-conversion 將其作為編譯器標志(compiler flag)進行傳遞。

它是做什麼的?

為了向大家更好地說明,試想有這麼一個命令行應用:

#import void welcomeToClowntown(NSString *_Nonnull greeting) {
  NSLog(@"%@, welcome to clowntown!", greeting);
}

int main(int argc, const char * argv[]) {
  // Warning: Null passed to a callee that requires 
  //          a non-null argument
  welcomeToClowntown(nil); 
  return 0;
}

注意到我們向函數 welcomeToClowntown() 中傳遞了一個 nil 字面量,即使這個函數接收的參數類型是 NSString *_Nonnull。不管 CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION 有無開啟,這都會引發一個警告。

但是下面這個例子又會如何呢?

#import void welcomeToClowntown(NSString *_Nonnull greeting) {
  NSLog(@"%@, welcome to clowntown!", greeting);
}

NSString *_Nullable clownyGreeting() {
  if (arc4random() % 2 == 0) {
    return @"Hola";
  } else {
    return nil;
  }
}

int main(int argc, const char * argv[]) {
  // *只有*在
  // CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION
  // 開啟的時候才會引發警告
  //
  // Warning: Implicit conversion from nullable pointer 
  //          'NSString * _Nullable' to non-nullable pointer
  //          type 'NSString * _Nonnull'
  welcomeToClowntown(clownyGreeting());
  return 0;
}

welcomeToClowntown() 需要傳遞一個 NSString *_Nonnull 類型的參數,然而我們為其傳遞的是 clownyGreeting() 函數的返回值,其類型是 NSString *_Nullable。換句話說,我們給一個需要非 nil 值的函數傳遞了一個可能為 nil 的值。CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION 針對這種情況會引發一個警告。

何時該使用它?

我建議在向 Objective-C 頭文件中添加可空標識符之前啟用這個功能。這樣,只要你給你的接口添加了不可空值的限制,那麼編譯器就會在違反這些限制的時候彈出警告。

這是否萬無一失?

並不是。和大多數編譯器警告相仿,它可以被規避掉:

#import void welcomeToClowntown(NSString *_Nonnull greeting) {
  NSLog(@"%@, welcome to clowntown!", greeting);
}

NSString *_Nullable clownyGreeting() {
  if (arc4random() % 2 == 0) {
    return @"Hola";
  } else {
    return nil;
  }
}

int main(int argc, const char * argv[]) {
  // 不再引發警告,因為返回類型
  // 被“強轉”為了一個(未明確聲明為不可空的) `NSString *`類型。
  NSString *greeting = clownyGreeting();
  welcomeToClowntown(greeting);
  return 0;
}

當我們獲取 clownyGreeting() 的值時,我們得到的是一個 NSString *_Nonnull,然後我們將其賦給了 NSString * 類型的變量,這導致編譯器不再提示警告。我想這是由於返回的 NSString *_Nonnull 對象被“強轉”為了 NSString * 類型,而這個類型沒有明確聲明是否可為空。

為什麼不要啟用這項警告?

可空標識符被添加到了諸如 NSString 之類的 Foundation 類當中,它們當中的某些判斷非常嚴格。比如說,-[NSString isEqualToString:] 接收的參數是 NSString *_Nonnull 類型。如果你有許多該方法的調用點,並且期望當傳入的參數為 nil 的時候,-isEqualToString: 將返回 NO 值(或許 JSON 解析之類的?),你就不得不修改這些調用點來消滅惱人的警告。

#import NSString *_Nullable clownyGreeting() {
  if (arc4random() % 2 == 0) {
    return @"Hola";
  } else {
    return nil;
  }
}

int main(int argc, const char * argv[]) {
  // *只有*在
  // CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION
  // 開啟的時候才會引發警告
  //
  // Warning: Implicit conversion from nullable pointer 
  //          'NSString * _Nullable' to non-nullable pointer
  //          type 'NSString * _Nonnull'
  [@"Hola" isEqualToString:clownyGreeting()];
  return 0;
}

這會讓編碼工作變得更為麻煩,因此注意:在項目中開啟 CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION 功能將會導致大量的警告出現!

不過,這些為 nil 的錯誤提示點或許會遍布於你的整個系統。你可以試著將這個功能打開,然後看看令人吃驚的結果吧!

感謝 @nlutsenko(https://twitter.com/nlutsenko) 為我介紹了這個設置項!

更新:Clang 靜態分析器改善

最新版本的 Clang 靜態分析器在2015年10月28號的時候發布。它能夠捕獲到我上面指出的“可規避點”的問題:

#import void welcomeToClowntown(NSString *_Nonnull greeting) {
  NSLog(@"%@, welcome to clowntown!", greeting);
}

NSString *_Nullable clownyGreeting() {
  if (arc4random() % 2 == 0) {
    return @"Hola";
  } else {
    return nil;
  }
}

int main(int argc, const char * argv[]) {
  // 此前不會引發警告,因為返回類型
  // 被“強轉”為了一個(未明確聲明為不可空的) `NSString *`類型。
  //
  // 最新的 Clang 靜態分析器則會引發警告:
  // Warning: Nullable pointer is passed to a callee
  //          that requires a non-null argument
  NSString *greeting = clownyGreeting();
  welcomeToClowntown(greeting);
  return 0;
}

這是一項極大的改進,我已等不及使用和 Xcode 共存的這個新分析器了。當然,你也可以下載最新的版本並運行以下代碼,就可以自行使用了。

$ checker-277/scan-build \
      -enable-checker nullability.NullPassedToNonnull \
      -enable-checker nullability.NullReturnedFromNonnull \
      -enable-checker nullability.NullableDereferenced \
      -enable-checker nullability.NullablePassedToNonnull \
      xcodebuild

本文中的所有譯文僅用於學習和交流目的,轉載請注明文章譯者、出處、和本文鏈接。
感謝博文視點為本期翻譯活動提供贊助

blob.png

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved