Avec Xcode 6.3, de nouvelles annotations ont été introduites pour mieux exprimer l'intention des API en Objective-C (et pour assurer un meilleur support Swift bien sûr). Ces annotations étaient bien sûr nonnull
, nullable
et null_unspecified
.
Mais avec Xcode 7, de nombreux avertissements apparaissent tels que:
Le pointeur n'a pas de spécificateur de type de nullabilité (_Nonnull, _Nullable ou _Null_unspecified).
En plus de cela, Apple utilise un autre type de spécificateurs de nullabilité, marquant leur code C ( source ):
CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
Donc, pour résumer, nous avons maintenant ces 3 annotations de nullabilité différentes:
nonnull
,nullable
,null_unspecified
_Nonnull
,_Nullable
,_Null_unspecified
__nonnull
,__nullable
,__null_unspecified
Même si je sais pourquoi et où utiliser quelle annotation, je ne sais pas trop quel type d'annotations dois-je utiliser, où et pourquoi. Voici ce que je pourrais comprendre:
- Pour les propriétés que je devrais utiliser
nonnull
,nullable
,null_unspecified
. - Pour les paramètres de la méthode que je devrais utiliser
nonnull
,nullable
,null_unspecified
. - Pour les méthodes C je devrais utiliser
__nonnull
,__nullable
,__null_unspecified
. - Pour d' autres cas, comme doubles pointeurs que je devrais utiliser
_Nonnull
,_Nullable
,_Null_unspecified
.
Mais je ne comprends toujours pas pourquoi nous avons tant d'annotations qui font essentiellement la même chose.
Ma question est donc:
Quelle est la différence exacte entre ces annotations, comment les placer correctement et pourquoi?
Réponses:
De la
clang
documentation :, et
Donc, pour les retours de méthode et les paramètres, vous pouvez utiliser les versions à double soulignement
__nonnull
/__nullable
/__null_unspecified
au lieu des versions à simple soulignement ou à la place des versions non soulignées. La différence est que les simples et doubles soulignés doivent être placés après la définition de type, tandis que les non soulignés doivent être placés avant la définition de type.Ainsi, les déclarations suivantes sont équivalentes et correctes:
Pour les paramètres:
Pour les propriétés:
Les choses se compliquent cependant lorsque des doubles pointeurs ou des blocs retournant quelque chose de différent de void sont impliqués, car les non-soulignés ne sont pas autorisés ici:
Similaire aux méthodes qui acceptent des blocs comme paramètres, veuillez noter que le qualificatif
nonnull
/nullable
s'applique au bloc, et non à son type de retour, donc les éléments suivants sont équivalents:Si le bloc a une valeur de retour, vous êtes forcé dans l'une des versions de soulignement:
En conclusion, vous pouvez utiliser l'un ou l'autre, tant que le compilateur peut déterminer l'élément auquel attribuer le qualificatif.
la source
_Null_unspecified
dans Swift, cela se traduit par facultatif? non facultatif ou quoi?Sur le blog Swift :
la source
J'ai vraiment aimé cet article , donc je montre simplement ce que l'auteur a écrit: https://swiftunboxed.com/interop/objc-nullability-annotations/
null_unspecified:
ponts vers un Swift implicitement déroulé en option. C'est la valeur par défaut .nonnull
: la valeur ne sera pas nulle; ponts vers une référence régulière.nullable
: la valeur peut être nulle; ponts à une option.null_resettable
: la valeur ne peut jamais être nulle lors de la lecture, mais vous pouvez la définir sur nil pour la réinitialiser. S'applique uniquement aux propriétés.Les notations ci-dessus, diffèrent alors si vous les utilisez dans le contexte de propriétés ou de fonctions / variables:
L'auteur de l'article a également fourni un bel exemple:
la source
Très pratique est
et en terminant avec
Cela annulera le besoin du niveau de code 'nullibis' :-) car il est en quelque sorte logique de supposer que tout est non nul (ou
nonnull
ou_nonnull
ou__nonnull
) sauf indication contraire.Malheureusement, il y a aussi des exceptions à cela ...
typedef
s ne sont pas supposés être__nonnull
(note,nonnull
ne semble pas fonctionner, faut utiliser son demi-frère moche)id *
a besoin d'un nullibi explicite mais wow le péché-tax (_Nullable id * _Nonnull
<- devinez ce que cela signifie ...)NSError **
est toujours supposé nullableDonc, à l'exception des exceptions et des mots-clés incohérents suscitant la même fonctionnalité, peut-être que l'approche consiste à utiliser les versions laides
__nonnull
/__nullable
/__null_unspecified
et à échanger lorsque le complicateur se plaint ...? C'est peut-être pourquoi ils existent dans les en-têtes Apple?Fait intéressant, quelque chose l'a mis dans mon code ... J'ai horreur des soulignements dans le code (type de style Apple C ++ de la vieille école) donc je suis absolument sûr que je ne les ai pas tapés mais ils sont apparus (un exemple parmi plusieurs):
Et encore plus intéressant, là où il a inséré le __nullable est faux ... (eek @!)
J'aimerais vraiment pouvoir utiliser la version non soulignée, mais apparemment, cela ne fonctionne pas avec le compilateur car cela est signalé comme une erreur:
la source