6

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":

enter image description here

Using Xcode 7.3 and iOS 9.3 documentation, I checked initWithFrame: and it can return nil:

description

But UIView.h encapsulates everything with NS_ASSUME_NONNULL_BEGIN, so we can interpret the following:

interface

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;
}

UPDATE

Xcode documentation was updated and is now: initWithFrame: documentation

So no more conflict.

Community
  • 1
  • 1
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 1
    It depends on what you mean by "trust". The compiler (and associated tooling) is going to "trust" the annotations, not the documentation. If you want your code to pass without warning, and not give headaches to Swift users, assume the `nonnull` attribute is correct. – Avi Feb 21 '16 at 07:09
  • Facing a similar issue with `[NSURL URLWithString:]`, as declaration wants the string to be `nonnull`, but description states it can be `nil`. – Cœur Feb 21 '16 at 14:09

2 Answers2

3

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.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Hello Devin. Thank you for answering. I wasn't the one to downvote you, as I know you work for Apple since [you replied to me in the past](https://llvm.org/bugs/show_bug.cgi?id=26143). I understand I should trust Apple's headers more, so I will remove defensive code for methods returning `nonnull instancetype`. – Cœur Feb 24 '16 at 01:31
  • Does this come from official sources, or it's an observation based on latest XCode beta's static analyzer behaviour? – Cristik Feb 24 '16 at 06:15
  • Devin, may you look at http://stackoverflow.com/q/34195149/1033581 as well? Or confirm that it is OK for [[AFURLSessionManager (nonnull instancetype)initWithSessionConfiguration:](https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFURLSessionManager.m#L511)] to return `nil`? – Cœur Feb 24 '16 at 06:20
1

The headers usually take precedence, as many times the documentation is either left behind or overlooked. UIKit (among the other CocoaTouch frameworks) headers are more up-to-date than the documentation for another reason: better Swift interoperability.

So you should go with the second approach:

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

Returning nonnull from this initializer is also logical, as an UIView is an abstract object that holds information about something that will eventually be rendered on the screen, it doesn't have many restrictions on it own.

Similarly, it doesn't make much sense to pass a nil string to [NSURL URLWithString:] as NSURL strings have clearly defined requirements, and a nil one doesn't satisfy them, so it makes sense to have the nonnull annotation here.

Cristik
  • 30,989
  • 25
  • 91
  • 127