转载

Clang 警告:可空值强转为不可空值

Clang 警告:可空值强转为不可空值

  • 本文由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

Clang 警告:可空值强转为不可空值

您可以使用 -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

本文中的所有译文仅用于学习和交流目的,转载请注明文章译者、出处、和本文链接。

感谢 博文视点 为本期翻译活动提供赞助

Clang 警告:可空值强转为不可空值

正文到此结束
Loading...