nullable : the value can be nil. It bridges to a Swift optional. null_resettable : the value can never be nil when read, but you can set it to nil to reset it.
If you want to make the method optional, you must specify the objc keyword as you have done, regardless if you are interoperating with Objective-C or not. At that point, everything else should work in your example.
id is the generic object pointer, an Objective-C type representing "any object". An instance of any Objective-C class can be stored in an id variable.
From the clang
documentation:
The nullability (type) qualifiers express whether a value of a given pointer type can be null (the
_Nullable
qualifier), doesn’t have a defined meaning for null (the_Nonnull
qualifier), or for which the purpose of null is unclear (the_Null_unspecified
qualifier). Because nullability qualifiers are expressed within the type system, they are more general than thenonnull
andreturns_nonnull
attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply.
, and
In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords
So for method returns and parameters you can use the
the double-underscored versions __nonnull
/__nullable
/__null_unspecified
instead of either the single-underscored ones, or instead of the non-underscored ones. The difference is that the single and double underscored ones need to be placed after the type definition, while the non-underscored ones need to be placed before the type definition.
Thus, the following declarations are equivalent and are correct:
- (nullable NSNumber *)result
- (NSNumber * __nullable)result
- (NSNumber * _Nullable)result
For parameters:
- (void)doSomethingWithString:(nullable NSString *)str
- (void)doSomethingWithString:(NSString * _Nullable)str
- (void)doSomethingWithString:(NSString * __nullable)str
For properties:
@property(nullable) NSNumber *status
@property NSNumber *__nullable status
@property NSNumber * _Nullable status
Things however complicate when double pointers or blocks returning something different than void are involved, as the non-underscore ones are not allowed here:
- (void)compute:(NSError * _Nullable * _Nullable)error
- (void)compute:(NSError * __nullable * _Null_unspecified)error;
// and all other combinations
Similar with methods that accept blocks as parameters, please note that the nonnull
/nullable
qualifier applies to the block, and not its return type, thus the following are equivalent:
- (void)executeWithCompletion:(nullable void (^)())handler
- (void)executeWithCompletion:(void (^ _Nullable)())handler
- (void)executeWithCompletion:(void (^ __nullable)())handler
If the block has a return value, then you're forced into one of the underscore versions:
- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler
- (void)convertObject:(id __nonnull (^ _Nullable)())handler
- (void)convertObject:(id _Nonnull (^ __nullable)())handler
// the method accepts a nullable block that returns a nonnull value
// there are some more combinations here, you get the idea
As conclusion, you can use either ones, as long as the compiler can determine the item to assign the qualifier to.
From the Swift blog:
This feature was first released in Xcode 6.3 with the keywords __nullable and __nonnull. Due to potential conflicts with third-party libraries, we’ve changed them in Xcode 7 to the _Nullable and _Nonnull you see here. However, for compatibility with Xcode 6.3 we’ve predefined macros __nullable and __nonnull to expand to the new names.
From the clang documentation:
The nullability (type) qualifiers express whether a value of a given pointer type can be null.
Most of the time you will use nonnull
and nullable
.
Below are all the available specifiers. From this article:
null_unspecified:
This is the default. It bridges to a Swift implicitly-unwrapped optional.nonnull
: the value won’t be nil. It bridges to a Swift regular reference.nullable
: the value can be nil. It bridges to a Swift optional.null_resettable
: the value can never be nil when read, but you can set it to nil to reset it. Applies to properties only.The notations above differ whether you use them in the context of properties or functions/variables:
The author of the article also provided a nice example:
// property style
@property (nonatomic, strong, null_resettable) NSString *name;
// pointer style
+ (NSArray<NSView *> * _Nullable)interestingObjectsForKey:(NSString * _Nonnull)key;
// these two are equivalent!
@property (nonatomic, strong, nullable) NSString *identifier1;
@property (nonatomic, strong) NSString * _Nullable identifier2;
Very handy is
NS_ASSUME_NONNULL_BEGIN
and closing with
NS_ASSUME_NONNULL_END
This will nullify the need for the code level 'nullibis' :-) as it sort of makes sense to assume that everything is non-null (or nonnull
or _nonnull
or __nonnull
) unless otherwise noted.
Unfortunately there are exceptions to this as well...
typedef
s are not assumed to be __nonnull
(note, nonnull
does not seem to work, have to use it's ugly half brother)id *
needs an explicit nullibi but wow the sin-tax ( _Nullable id * _Nonnull
<- guess what that means...)NSError **
is always assumed nullableSo with the exceptions to the exceptions and the inconsistent keywords eliciting the same functionality, perhaps the approach is to use the ugly versions __nonnull
/ __nullable
/ __null_unspecified
and swap when the complier complains... ? Maybe that is why they exist in the Apple headers?
Interestingly enough, something put it into my code... I abhor underscores in code (old school Apple C++ style guy) so I am absolutely sure I did not type these but they appeared (one example of several):
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * __nullable credential );
And even more interestingly, where it inserted the __nullable is wrong... (eek@!)
I really wish I could just use the non-underscore version but apparently that does not fly with the compiler as this is flagged as an error:
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * nonnull credential );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With