`[UIView initWithFrame:]`的文档冲突:可空或非空?

时间:2016-02-21 05:48:23

标签: ios objective-c uiview initwithframe objective-c-nullability

使用CLANG_ANALYZER_NONNULL(即-Xclang nullability),我得到“ Null从一个预期会返回非空值的函数返回”:

enter image description here

使用Xcode 7.3和iOS 9.3文档,我检查了initWithFrame:,它可以返回nil

description

但是UIView.h用NS_ASSUME_NONNULL_BEGIN封装了所有内容,因此我们可以解释以下内容:

interface

为:

- (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文档已更新,现在是: initWithFrame: documentation

所以不再有冲突。

2 个答案:

答案 0 :(得分:3)

对于UIView的{​​{1}}初始化程序,建议不要在防御性方面检查调用超级初始化程序的结果,因为实际上没有任何应用程序可以从失败中恢复{ {1}}分配。

此外,从Xcode 7.3 beta 4开始,静态分析仪不再在此处发出警告。它现在不会警告从-initWithFrameUIView-init系列返回nil,即使这些方法具有带-copy类型限定符的返回类型以避免警告正是这种常见的防御习语。

答案 1 :(得分:1)

标题通常优先,因为很多时候文档要么被遗忘要么被忽略了。 UIKit(在其他CocoaTouch框架中)标题由于其他原因而比文档更新:更好Swift互操作性。

所以你应该采用第二种方法:

- (nonnull instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    // Initialization code
    return self;
}

从这个初始化程序返回nonnull也是合乎逻辑的,因为UIView是一个抽象对象,它包含最终将在屏幕上呈现的内容的信息,它没有很多限制就自己而言。

同样,将{0}字符串传递给[NSURL URLWithString:]并没有多大意义,因为NSURL字符串有明确定义的要求,nil一个字符串没有满足它们,所以在这里使用nonnull注释是有意义的。