xcode Clang为空性警告以及如何处理它们

vh0rcniy  于 2023-06-24  发布在  其他
关注(0)|答案(2)|浏览(144)

最近,我在Xcode中打开了CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION,我被Objective-C代码中与空性相关的警告淹没了。最常见的一种警告类型是Implicit conversion from nullable pointer 'TypeA * _Nullable' to non-nullable pointer type 'TypeA * _Nonnull'
我开始尝试删除这些警告,方法是在方法中创建一个相同类型的本地文件,如本文所述。https://www.mail-archive.com/xcode-users%40lists.apple.com/msg02260.html这篇文章说,首先使用一个本地,该对象的属性是未指定的nullable,所以它可以作为合法的参数,以期望非空的方法。
但我觉得这是一个逃避的举动,并没有以任何有益的方式解决问题。
有人已经做过这个练习了吗?如果你能分享你采取的策略,我将不胜感激。

7y4bm7vi

7y4bm7vi1#

不是所有的警告都有意义。有时这是编译器的一个缺点。例如,这段代码不需要警告。

- (nullable id)transformedValue:(nullable id)value {
    id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
    return result;
}

我们正在检查它是否为null!我们还能做什么?为什么要创建一个额外的指针?
所以,我们这样做:

- (nullable id)transformedValue:(nullable id)value {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion"
    id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
#pragma clang diagnostic pop
    return result;
}

为什么这是正确的答案?
首先,比编译器聪明是可以的。你不想因为一个虚假的警告而开始破坏你的代码。
此解决方案指定要隐藏的确切警告消息,并且只隐藏一行。

gojuced7

gojuced72#

事实上,我已经在这个主题上花了一点时间。我想在一个有点大的项目中改善空性的情况(使其更“迅速”)。这是我发现的。
首先,您应该打开CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION-Wnullable-to-nonnull-conversion
其次,关于
首先使用一个local,该对象的属性未指定为nullable,因此它可以用作期望非null的方法的合法参数。
这很糟糕,我创建了一个名为NONNUL_CAST()的宏。下面是如何实现它的示例:

#define NONNUL_CAST(__var) ({ NSCAssert(__var, @"Variable is nil");\
    (__typeof(*(__var))* _Nonnull)__var; })

在这里你可以看到hacky __typeof(*(__var))* _Nonnull)__var,但它并不那么糟糕。如果__var的类型是A* _Nullable,我们解引用__var,所以它的类型现在只是A,在我们再次引用之后,而是_Nonnull,并得到非空的__var作为答案。我们当然会这么说,以防万一。
第三,你必须在每个局部变量上指定nullabilty,你应该把所有的代码放在NS_ASSUME_NONNULL_BEGIN/END中,像这样:

NS_ASSUME_NONNULL_BEGIN 
<your_code_goes_here>
NS_ASSUME_NONNULL_END`

你把代码的 * 每一行 *(除了导入)都放在.h.m文件中。这将假设所有方法的参数,返回类型和属性都是非空的。如果你想让它可以为空,就在这里加上nullable。
好了,都做完了,现在怎么办?以下是典型用法的示例:

- (Atype*)makeAtypeWithBtype:(nullable BType*)btype {
  Atype* _Nullable a = [btype makeAtype];
  if (a) {
    // All good here.
    return NONNUL_CAST(a);
  } else {
    // a appeared as nil. Some fallback is needed.
    [self reportError];
    return [AtypeFactory makeDeafult];
  }
}

现在你有了更强大的空性情况。也许它看起来不太好,但它是客观的c,所以没有什么可抱怨的。

更新

与块类型一起工作的宏(也可能与函数类型一起工作):

@interface __NONNULL_CASTER <__covariant T>
+ (T _Nonnull)nonnullCaster;
@end

#define NONNUL_CAST(__var)                                      \
  ({                                                            \
    __typeof(__var) __local_var = __var;                        \
    NSCAssert(__local_var##__id != nil);                        \
    (__typeof([__NONNULL_CASTER<__typeof(__var)> nonnullCast])) \
        __local_var;                                            \
  })

相关问题