118

Consider the following method

- (void)methodWithArg:(NSString *)arg1 andArg:(NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;

With the new nonnull and nullable annotation keywords we can enrich it as follows:

- (void)methodWithArg:(nonnull NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;

but we also get this warning:

Pointer is missing a nullability type specifier (__nonnull or __nullable)

It refers to the third parameter (the block one).

The documentation doesn't cover with examples how to specify the nullability of block parameters. It states verbatim

You can use the non-underscored forms nullable and nonnull immediately after an open parenthesis, as long as the type is a simple object or block pointer.

I tried putting one of the two keywords for the block (in any position) without any luck. Also tried the underscore prefixed variants (__nonnull and __nullable).

Therefore my question is: how can I specify the nullability semantic for block parameters?

mylogon
  • 2,772
  • 2
  • 28
  • 42
albertodebortoli
  • 1,768
  • 2
  • 16
  • 20

6 Answers6

146

This seems to be working

- (void)methodWithArg:(nonnull NSString *)arg1 
  andArg:(nullable NSString *)arg2 completionHandler:(nullable void (^)
  (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler

You need to specify nullability both for the block and its parameters...

EDIT: For more information, see Swift Blog

neontapir
  • 4,698
  • 3
  • 37
  • 52
Fabio Ritrovato
  • 2,546
  • 1
  • 13
  • 19
  • How does that work with the `NSError **` type? I can't seem to make the compiler happy. – duhanebel May 16 '15 at 11:56
  • 3
    According to the swift blog: `The particular type NSError ** is so often used to return errors via method parameters that it is always assumed to be a nullable pointer to a nullable NSError reference.` https://developer.apple.com/swift/blog/?id=25 – user1687195 May 28 '15 at 16:24
  • 1
    @duhanebel The answer is given in http://stackoverflow.com/questions/33198597/nserror-swift-and-nullability: (NSError * _Nullable *_Nullable) error – Elise van Looij Sep 10 '16 at 13:27
40

According to Apple Blog ("Nullability and Objective-C"), you can use

NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END.

Within these regions, any simple pointer type will be assumed to be nonnull. Then you can just add nullable for nullable object, which like

NS_ASSUME_NONNULL_BEGIN

@interface MyClass: NSObject

- (void)methodWithArg:(NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;

@end

NS_ASSUME_NONNULL_END
  • if error is NSError ** type, should be NSError * _Nullable * _Nullable
  • if object is id * type, better use id _Nullable * _Nonnull, it depends (may be you want a _Nullable id * _Nullable type).
  • if object is NSObject * type, you need put annotation after pointer, like this NSObject * _Nullable * _Nonnull

Note

_Nonnull and _Nullable should used after pointer or id (Apple does in the example code AAPLListItem * _Nullable), but the non-underscored forms nonnull and nullable can used after an open parenthesis.

However, in the common case there’s a much nicer way to write these annotations: within method declarations you can use the non-underscored forms nullable and nonnull immediately after an open parenthesis, as long as the type is a simple object or block pointer.

check more in "Nullability and Objective-C"

For safety, there are a few exceptions to this rule:

  • typedef types don’t usually have an inherent nullability—they can easily be either nullable or non-nullable depending on the context. Therefore, typedef types are not assumed to be nonnull, even within audited regions.
  • More complex pointer types like id * must be explicitly annotated. For example, to specify a non-nullable pointer to a nullable object reference, use _Nullable id * _Nonnull.
  • The particular type NSError ** is so often used to return errors via method parameters that it is always assumed to be a nullable pointer to a nullable NSError reference.

The _Nullable id * _Nonnull can be confused, id _Nullable * _Nonnull is better understanding.

_Nonnull and _Nullable should used after pointer or id (Apple does in the example code AAPLListItem * _Nullable)

likid1412
  • 963
  • 8
  • 15
4

You can also do like this:

- (id __nullable)methodWithArg:(NSString * __nullable)arg1
                        andArg:(NSString * __nonnull)arg2
             completionHandler:(void (^ __nonnull)(NSArray * __nonnull results, NSError * __nullable error))completionHandler;

It only depends which syntax you like more.

OlDor
  • 1,460
  • 12
  • 18
  • can you elaborate just a little more on the MEANING of what you defined? Do I get it right that the code-block is REQUIRED for this method, and cannot be nil? I tried to add the _Nonnull before the last parenthesis NSError * __nullable error) _Nonnull )completionHandler; and got a nasty compiler error for that. – Motti Shneor Apr 19 '21 at 08:42
2

To define completions in a header file I did this

typedef void (^PublicEventsHandler) (BOOL success, NSArray * _Nullable publicEvents);

Of course, I agree with the accepted answer.

Krishna Kumar
  • 187
  • 1
  • 17
0

From apple developer blog: The Core: _Nullable and _Nonnull

you can use the non-underscored forms nullable and nonnull immediately after an open parenthesis, as long as the type is a simple object or block pointer.

The non-underscored forms are nicer than the underscored ones, but you’d still need to apply them to every type in your header.

Community
  • 1
  • 1
Parag Bafna
  • 22,812
  • 8
  • 71
  • 144
-2

Here is what I have used for the NSError ** case:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;
Brian
  • 14,610
  • 7
  • 35
  • 43
Kevin
  • 19
  • 1
  • 1
    As [Apple](https://developer.apple.com/swift/blog/?id=25) said, for `NSError **`, you have no need to specify its nullability. – DawnSong Dec 04 '18 at 08:04