Using CLANG_ANALYZER_NONNULL
(i.e. -Xclang nullability
), I got "Null is returned from a function that is expected to return a non-null value":
Using Xcode 7.3 and iOS 9.3 documentation, I checked initWithFrame:
and it can return nil
:
But UIView.h encapsulates everything with NS_ASSUME_NONNULL_BEGIN
, so we can interpret the following:
as:
- (nonnull instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
So documentation explains it's nullable
, while header file says it's nonnull
. Which one to trust?
Should I write:
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
// workaround for clang analyzer
return (void * _Nonnull)nil;
}
// Initialization code
return self;
}
Or:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
🔴🔴🔴
Xcode documentation was updated and is now:
So no more conflict.
In the case of UIView
's -initWithFrame
initializer, the recommendation is to not defensively check the result of calling the super initializer because there is realistically nothing an application can do to recover from a failed UIView
allocation.
Also, as of Xcode 7.3 beta 4, the static analyzer no longer warns here. It now doesn't warn about returning nil from the -init
, -copy
, and -mutableCopy
families even when these methods have a return type with a nonnull
type qualifier to avoid warning on exactly this common defensive idiom.