Противоречивая документация для `[UIView initWithFrame:]`: обнуляемый или ненулевой?

С помощью CLANG_ANALYZER_NONNULL (т.е. -Xclang nullability), Я получил " Null возвращается из функции, которая должна возвращать ненулевое значение ":

введите описание изображения здесь

Используя документацию Xcode 7.3 и iOS 9.3, я проверил initWithFrame: и он может вернуться 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 была обновлена ​​и теперь: initWithFrame: документация

Так что больше нет конфликтов.

2 ответа

Решение

В случае UIView"s -initWithFrame инициализатор, рекомендуется не проверять результат вызова супер инициализатора, потому что приложение не может реально ничего сделать для восстановления после сбоя UIView распределение.

Также, начиная с Xcode 7.3 beta 4, статический анализатор здесь больше не предупреждает. Теперь он не предупреждает о возвращении ноль из -init, -copy, а также -mutableCopy семьи, даже когда эти методы имеют тип возврата с nonnull квалификатор типа, чтобы избежать предупреждения именно об этой общепринятой оборонительной фразеологии.

Заголовки обычно имеют приоритет, так как часто документация либо остается позади, либо игнорируется. UIKit (среди других CocoaTouch рамки) заголовки являются более современными, чем документация по другой причине: лучше Swift совместимость.

Таким образом, вы должны пойти со вторым подходом:

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

возврате nonnull из этого инициализатора также логично, как UIView является абстрактным объектом, который содержит информацию о чем-то, что в конечном итоге будет отображаться на экране, но у него нет особых ограничений.

Точно так же не имеет большого смысла передавать ноль строку [NSURL URLWithString:] как NSURL Строки имеют четко определенные требования, и nil никто не удовлетворяет их, поэтому имеет смысл иметь nonnull аннотация здесь.

Другие вопросы по тегам