Противоречивая документация для `[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 была обновлена и теперь:
Так что больше нет конфликтов.
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
аннотация здесь.