Comment utiliser des mots-clés Objective-C non nuls et Nullable dans la méthode API basée sur des blocs

105

Considérez la méthode suivante

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

Avec les mots-clés new nonnullet nullable annotation, nous pouvons l'enrichir comme suit:

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

mais nous obtenons également cet avertissement:

Le pointeur n'a pas de spécificateur de type de nullabilité (__nonnull ou __nullable)

Il fait référence au troisième paramètre (le bloc un).

La documentation ne couvre pas avec des exemples comment spécifier la nullité des paramètres de bloc. Il déclare textuellement

Vous pouvez utiliser les formes non soulignées Nullable et Nonnull immédiatement après une parenthèse ouverte, à condition que le type soit un simple objet ou un pointeur de bloc.

J'ai essayé de mettre l'un des deux mots-clés pour le bloc (dans n'importe quelle position) sans aucune chance. Également essayé les variantes préfixées de soulignement ( __nonnullet __nullable).

Par conséquent, ma question est: comment puis-je spécifier la sémantique de nullabilité pour les paramètres de bloc?

Albertodebortoli
la source

Réponses:

128

Cela à l'air de marcher

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

Vous devez spécifier la nullité à la fois pour le bloc et ses paramètres ...

EDIT: Pour plus d'informations, voir Swift Blog

Fabio Ritrovato
la source
Comment cela fonctionne-t-il avec le NSError **type? Je n'arrive pas à rendre le compilateur heureux.
duhanebel
3
Selon le blog swift: 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. developer.apple.com/swift/blog/?id=25
user1687195
@duhanebel La réponse est donnée dans stackoverflow.com/questions/33198597/… : (NSError * _Nullable * _Nullable) error
Elise van Looij
33

Selon Apple Blog ("Nullability and Objective-C") , vous pouvez utiliser

NS_ASSUME_NONNULL_BEGINet NS_ASSUME_NONNULL_END.

Dans ces régions, tout type de pointeur simple sera supposé être nonnull. Ensuite, vous pouvez simplement ajouter nullableun objet Nullable, qui comme

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
  • si l' erreur est de NSError **type, devrait êtreNSError * _Nullable * _Nullable
  • si l'objet est de id *type, meilleure utilisation id _Nullable * _Nonnull, cela dépend (peut-être voulez-vous un _Nullable id * _Nullabletype).
  • si l'objet est de NSObject *type, vous devez mettre une annotation après le pointeur, comme ceciNSObject * _Nullable * _Nonnull

Remarque

_Nonnullet _Nullabledoit être utilisé après le pointeur ou id(Apple le fait dans l'exemple de code AAPLListItem * _Nullable), mais les formulaires non soulignés nonnullet nullablepeuvent être utilisés après une parenthèse ouverte.

Cependant, dans le cas courant, il existe une manière beaucoup plus agréable d'écrire ces annotations: dans les déclarations de méthode, vous pouvez utiliser les formes non soulignées nullableet nonnullimmédiatement après une parenthèse ouverte, tant que le type est un simple objet ou un pointeur de bloc.

vérifier plus dans "Nullabilité et Objective-C"

Pour des raisons de sécurité, il existe quelques exceptions à cette règle:

  • typedefLes types n'ont généralement pas de possibilité de valeur Null inhérente - ils peuvent facilement être Nullable ou non Nullable selon le contexte. Par conséquent, les typedeftypes ne sont pas supposés l'être nonnull, même dans les régions auditées.
  • Les types de pointeurs plus complexes comme id *doivent être explicitement annotés. Par exemple, pour spécifier un pointeur non Nullable vers une référence d'objet Nullable, utilisez _Nullable id * _Nonnull.
  • Le type particulier NSError **est si souvent utilisé pour renvoyer des erreurs via des paramètres de méthode qu'il est toujours supposé être un pointeur Nullable vers une NSErrorréférence Nullable .

Le _Nullable id * _Nonnullpeut être confus, id _Nullable * _Nonnullc'est une meilleure compréhension.

_Nonnullet _Nullabledoit être utilisé après le pointeur ou id(Apple le fait dans l'exemple de codeAAPLListItem * _Nullable )

likid1412
la source
Pour une propriété faible, _Nullable est appliqué.
Dongjin Suh
3

Vous pouvez également faire comme ceci:

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

Cela dépend uniquement de la syntaxe que vous préférez.

OlDor
la source
2

Pour définir les complétions dans un fichier d'en-tête, j'ai fait ceci

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

Bien sûr, je suis d'accord avec la réponse acceptée.

Krishna Kumar
la source
0

Du blog des développeurs Apple : The Core: _Nullable et _Nonnull

vous pouvez utiliser les formes non soulignées Nullable et Nonnull immédiatement après une parenthèse ouverte , tant que le type est un simple objet ou un pointeur de bloc.

Les formulaires non soulignés sont plus agréables que ceux soulignés, mais vous devrez toujours les appliquer à tous les types de votre en-tête .

Parag Bafna
la source
Ouais, mais les non-soulignés (plus gentils) ne fonctionnent pas dans les déclarations de bloc
Paul Bruneau
-2

Voici ce que j'ai utilisé pour le cas NSError **:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;
Kevin
la source
1
Comme Apple l'a dit, pour NSError **, vous n'avez pas besoin de spécifier sa nullité.
DawnSong