Ios 叮当作响的可空性警告以及如何处理它们
最近我在Xcode中打开了Ios 叮当作响的可空性警告以及如何处理它们,ios,objective-c,xcode,objective-c-nullability,Ios,Objective C,Xcode,Objective C Nullability,最近我在Xcode中打开了CLANG\u WARN\u NULLABLE\u TO\u NONNULL\u转换,我的Objective-C代码中与nullability相关的警告让我不知所措。最常见的一种警告类型是从可空指针“TypeA*\u nullable”隐式转换为不可空指针类型“TypeA*\u Nonnull” 我开始尝试删除这些警告,方法是在这里描述的方法中创建一个相同类型的本地。 本文说,通过首先使用local,该对象的属性为unspecified nullable,因此可以将其用
CLANG\u WARN\u NULLABLE\u TO\u NONNULL\u转换
,我的Objective-C代码中与nullability相关的警告让我不知所措。最常见的一种警告类型是从可空指针“TypeA*\u nullable”隐式转换为不可空指针类型“TypeA*\u Nonnull”
我开始尝试删除这些警告,方法是在这里描述的方法中创建一个相同类型的本地。
本文说,通过首先使用local,该对象的属性为unspecified nullable,因此可以将其用作预期为nonnull的方法的合法参数
但我觉得这是一种逃避行为,并不能以任何有益的方式解决问题
有人已经做过这个练习了吗?如果你能分享你采取的策略,我将不胜感激。事实上,我已经把这个话题弄得一团糟了。我想在一个有点大的项目中改善可空性的情况(使它更“快速”)。这是我发现的 首先,您应该打开
CLANG\u WARN\u NULLABLE\u TO\u NONNULL\u转换
(-Wnullable TO NONNULL转换
)
第二,关于
首先使用一个局部变量,该对象的属性未指定为null,
因此,它可以用作预期为非null的方法的合法参数
这很难闻,我创建了一个名为NONNUL\u CAST()
的宏。下面是如何实现它的示例:
#define NONNUL_CAST(__var) ({ NSCAssert(__var, @"Variable is nil");\
(__typeof(*(__var))* _Nonnull)__var; })
在这里你可以看到hacky\uuuuutypeof(*(\uuuuvar))*\uunonnull)\uuuuuvar
,但它并没有那么糟糕。如果\uuu var
类型为A*\u Nullable
我们取消引用\uu var
,那么在我们再次引用之后,它现在是A
,但是\u Nonnull
,并得到非null\uu var
作为答案。当然,如果出了什么问题,我们会坚持的
第三,您必须为每个局部变量指定可空性,并且您应该将所有代码放入NS\u ascape\u NONNULL\u BEGIN/END
,如下所示:
NS_ASSUME_NONNULL_BEGIN
<your_code_goes_here>
NS_ASSUME_NONNULL_END`
现在您有了更健壮的可空性情况。可能它看起来不太好看,但它是objective-c,所以没什么好抱怨的。事实上,我已经把这个话题弄得一团糟了一点。我想在一个有点大的项目中改善可空性的情况(使它更“快速”)。这是我发现的 首先,您应该打开
CLANG\u WARN\u NULLABLE\u TO\u NONNULL\u转换
(-Wnullable TO NONNULL转换
)
第二,关于
首先使用一个局部变量,该对象的属性未指定为null,
因此,它可以用作预期为非null的方法的合法参数
这很难闻,我创建了一个名为NONNUL\u CAST()
的宏。下面是如何实现它的示例:
#define NONNUL_CAST(__var) ({ NSCAssert(__var, @"Variable is nil");\
(__typeof(*(__var))* _Nonnull)__var; })
在这里你可以看到hacky\uuuuutypeof(*(\uuuuvar))*\uunonnull)\uuuuuvar
,但它并没有那么糟糕。如果\uuu var
类型为A*\u Nullable
我们取消引用\uu var
,那么在我们再次引用之后,它现在是A
,但是\u Nonnull
,并得到非null\uu var
作为答案。当然,如果出了什么问题,我们会坚持的
第三,您必须为每个局部变量指定可空性,并且您应该将所有代码放入NS\u ascape\u NONNULL\u BEGIN/END
,如下所示:
NS_ASSUME_NONNULL_BEGIN
<your_code_goes_here>
NS_ASSUME_NONNULL_END`
现在您有了更健壮的可空性情况。也许它看起来不好看,但它是客观的,所以没有什么好抱怨的。不是每个警告都有意义。有时这是编译器的一个缺点。例如,此代码不需要警告
- (nullable id)transformedValue:(nullable id)value {
id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
return result;
}
我们正在检查它是否为空!我们还能做什么?为什么要创建一个额外的指针
因此,我们这样做:
- (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;
}
为什么这是正确的答案
首先,可以比编译器更聪明。你不想仅仅因为一个虚假的警告就开始破坏你的代码
此解决方案指定了要抑制的确切警告消息,并且仅在一行中抑制该消息。并非每个警告都有意义。有时这是编译器的一个缺点。例如,此代码不需要警告
- (nullable id)transformedValue:(nullable id)value {
id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
return result;
}
我们正在检查它是否为空!我们还能做什么?为什么要创建一个额外的指针
因此,我们这样做:
- (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;
}
为什么这是正确的答案
首先,可以比编译器更聪明。你不想仅仅因为一个虚假的警告就开始破坏你的代码
此解决方案指定了要抑制的确切警告消息,并且仅抑制一行。您试图解决的问题是什么?当您知道对象不是零时抑制警告?还是确保对象不是零的实际过程?@dan假设我有如下代码:
NSMutableData*someData=[NSMutableData dataWithCapacity:d1000];[someData appendData:[NSString stringWithFormat:@“我想赢$%d”,1000000]代码>。因为appendData:
需要非空值,所以解决方法是在调用之前首先创建NSString*。理想情况下,我不想这样做,因为它只是添加了额外的代码行,试图解决这个问题,但实际上没有给我任何好处。好处是警告不再存在。这是否值得额外的代码行取决于您。我看不出有任何问题。[nsstringwithformat:
可以返回nil
,也不能返回。无论哪种方式,我都不明白为什么分配给中间变量会产生不同。如果编译器假设这样一个变量不是nil
,那么编译器就坏了,我会禁用这个警告。你想解决什么问题?当您知道对象不是零时抑制警告?还是确保对象不是零的实际过程?@dan假设我有如下代码:NSMutableData*someData=[NSMutableData dataWithCapacity:d1000];[someData appendData:[NSSt]