`[UIView initWithFrame:]` 的冲突文档:可空还是非空?
Conflicting documentation for `[UIView initWithFrame:]`: nullable or nonnull?
使用 CLANG_ANALYZER_NONNULL
(即 -Xclang nullability
),我得到了“Null is returned from a function that expected to return a non -空值":
使用 Xcode 7.3 和 iOS 9.3 文档,我检查了 initWithFrame:
它可以 return nil
:
但是UIView.h用NS_ASSUME_NONNULL_BEGIN
封装了所有东西,所以我们可以解读如下:
如:
- (nonnull instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
所以文档解释它是 nullable
,而头文件说它是 nonnull
。相信哪一个?
我应该写:
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
// workaround for clang analyzer
return (void * _Nonnull)nil;
}
// Initialization code
return self;
}
或者:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
更新
Xcode 文档已更新,现在:
所以没有更多的冲突。
headers 通常优先,因为很多时候文档要么被遗忘要么被忽视。 UIKit
(在其他 CocoaTouch
框架中)headers 比文档更多 up-to-date 另一个原因:更好的 Swift
互操作性。
所以你应该采用第二种方法:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
从这个初始化器返回 nonnull
也是合乎逻辑的,因为 UIView
是一个抽象 object,它包含有关最终将在屏幕上呈现的东西的信息,它不会它本身没有很多限制。
同样,将 nil 字符串传递给 [NSURL URLWithString:]
没有多大意义,因为 NSURL
字符串有明确定义的要求,而 nil
不能满足它们, 所以这里有 nonnull
注释是有意义的。
对于 UIView
的 -initWithFrame
初始化程序,建议不要防御性地检查调用超级初始化程序的结果,因为实际上应用程序无法从UIView
分配失败。
此外,从 Xcode 7.3 beta 4 开始,静态分析器不再在此处发出警告。它现在不会警告来自 -init
、-copy
和 -mutableCopy
系列的 returning nil,即使这些方法的 return 类型带有 nonnull
类型限定符以避免对这个常见的防御性习语发出警告。
使用 CLANG_ANALYZER_NONNULL
(即 -Xclang nullability
),我得到了“Null is returned from a function that expected to return a non -空值":
使用 Xcode 7.3 和 iOS 9.3 文档,我检查了 initWithFrame:
它可以 return nil
:
但是UIView.h用NS_ASSUME_NONNULL_BEGIN
封装了所有东西,所以我们可以解读如下:
如:
- (nonnull instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
所以文档解释它是 nullable
,而头文件说它是 nonnull
。相信哪一个?
我应该写:
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
// workaround for clang analyzer
return (void * _Nonnull)nil;
}
// Initialization code
return self;
}
或者:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
更新
Xcode 文档已更新,现在:
所以没有更多的冲突。
headers 通常优先,因为很多时候文档要么被遗忘要么被忽视。 UIKit
(在其他 CocoaTouch
框架中)headers 比文档更多 up-to-date 另一个原因:更好的 Swift
互操作性。
所以你应该采用第二种方法:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
从这个初始化器返回 nonnull
也是合乎逻辑的,因为 UIView
是一个抽象 object,它包含有关最终将在屏幕上呈现的东西的信息,它不会它本身没有很多限制。
同样,将 nil 字符串传递给 [NSURL URLWithString:]
没有多大意义,因为 NSURL
字符串有明确定义的要求,而 nil
不能满足它们, 所以这里有 nonnull
注释是有意义的。
对于 UIView
的 -initWithFrame
初始化程序,建议不要防御性地检查调用超级初始化程序的结果,因为实际上应用程序无法从UIView
分配失败。
此外,从 Xcode 7.3 beta 4 开始,静态分析器不再在此处发出警告。它现在不会警告来自 -init
、-copy
和 -mutableCopy
系列的 returning nil,即使这些方法的 return 类型带有 nonnull
类型限定符以避免对这个常见的防御性习语发出警告。