En tant que développeur Java qui lit la documentation Objective-C 2.0 d'Apple: je me demande ce que signifie « envoyer un message à nil » - sans parler de son utilité. Prenant un extrait de la documentation:
Il existe plusieurs modèles dans Cocoa qui profitent de ce fait. La valeur renvoyée par un message à nil peut également être valide:
- Si la méthode retourne un objet, tout type de pointeur, tout scalaire entier de taille inférieure ou égale à sizeof (void *), un float, un double, un long double ou un long long, alors un message envoyé à nil renvoie 0 .
- Si la méthode renvoie une structure, telle que définie par le Guide des appels de fonction ABI de Mac OS X à renvoyer dans les registres, un message envoyé à nil renvoie 0,0 pour chaque champ de la structure de données. Les autres types de données de structure ne seront pas remplis de zéros.
- Si la méthode renvoie autre chose que les types valeur mentionnés ci-dessus, la valeur de retour d'un message envoyé à nil n'est pas définie.
Java a-t-il rendu mon cerveau incapable de comprendre l'explication ci-dessus? Ou y a-t-il quelque chose qui me manque qui rendrait cela aussi clair que du verre?
J'ai l'idée de messages / récepteurs en Objective-C, je suis simplement confus au sujet d'un récepteur qui se trouve être nil
.
objective-c
Ryan Delucchi
la source
la source
Réponses:
Eh bien, je pense que cela peut être décrit à l'aide d'un exemple très artificiel. Disons que vous avez une méthode en Java qui imprime tous les éléments d'un ArrayList:
Maintenant, si vous appelez cette méthode comme ceci: someObject.foo (NULL); vous allez probablement avoir une NullPointerException quand il essaiera d'accéder à la liste, dans ce cas dans l'appel à list.size (); Maintenant, vous n'appeleriez probablement jamais someObject.foo (NULL) avec la valeur NULL comme ça. Cependant, vous avez peut-être obtenu votre ArrayList à partir d'une méthode qui renvoie NULL si elle rencontre une erreur générant la ArrayList comme someObject.foo (otherObject.getArrayList ());
Bien sûr, vous aurez également des problèmes si vous faites quelque chose comme ceci:
Maintenant, en Objective-C, nous avons la méthode équivalente:
Maintenant, si nous avons le code suivant:
nous avons la même situation dans laquelle Java produira une NullPointerException. L'objet nil sera accédé en premier à [anArray count] Cependant, au lieu de lancer une NullPointerException, Objective-C renverra simplement 0 conformément aux règles ci-dessus, donc la boucle ne fonctionnera pas. Cependant, si nous définissons la boucle pour qu'elle s'exécute un certain nombre de fois, nous envoyons d'abord un message à anArray at [anArray objectAtIndex: i]; Cela retournera également 0, mais puisque objectAtIndex: renvoie un pointeur, et un pointeur sur 0 est nul / NULL, NSLog sera passé nil à chaque fois dans la boucle. (Bien que NSLog soit une fonction et non une méthode, il imprime (null) s'il est passé un NSString nul.
Dans certains cas, il est plus agréable d'avoir une NullPointerException, car vous pouvez dire tout de suite que quelque chose ne va pas avec le programme, mais à moins que vous n'attrapiez l'exception, le programme plantera. (En C, essayer de déréférencer NULL de cette manière provoque le blocage du programme.) En Objective-C, cela provoque simplement un comportement d'exécution éventuellement incorrect. Cependant, si vous avez une méthode qui ne s'arrête pas si elle renvoie 0 / nil / NULL / une structure remise à zéro, cela vous évite d'avoir à vérifier que l'objet ou les paramètres sont nuls.
la source
myObject->iVar
il plantera, peu importe si c'est C avec ou sans objets. (désolé pour gravedig.)->
n'est plus une opération Objective-C mais bien un C-isme générique.Un message
nil
ne fait rien et retournenil
,Nil
,NULL
,0
ou0.0
.la source
Tous les autres articles sont corrects, mais c'est peut-être le concept qui est important ici.
Dans les appels de méthode Objective-C, toute référence d'objet qui peut accepter un sélecteur est une cible valide pour ce sélecteur.
Cela économise BEAUCOUP de "l'objet cible est-il de type X?" code - tant que l'objet récepteur implémente le sélecteur, il ne fait absolument aucune différence de quelle classe il s'agit!
nil
est un NSObject qui accepte n'importe quel sélecteur - il ne fait rien. Cela élimine également beaucoup de code "vérifier pour nil, ne pas envoyer le message si vrai". (Le concept "s'il l'accepte, il l'implémente" est aussi ce qui vous permet de créer des protocoles , qui sont un peu comme les interfaces Java: une déclaration selon laquelle si une classe implémente les méthodes indiquées, alors elle est conforme au protocole.)La raison en est d'éliminer le code singe qui ne fait rien d'autre que de satisfaire le compilateur. Oui, vous obtenez la surcharge d'un appel de méthode supplémentaire, mais vous gagnez du temps au programmeur , qui est une ressource beaucoup plus coûteuse que le temps CPU. De plus, vous éliminez plus de code et plus de complexité conditionnelle de votre application.
Clarification pour les votants négatifs: vous pensez peut-être que ce n'est pas une bonne voie à suivre, mais c'est la manière dont le langage est implémenté, et c'est l'idiome de programmation recommandé en Objective-C (voir les conférences de programmation iPhone de Stanford).
la source
Cela signifie que le runtime ne produit pas d'erreur lorsque objc_msgSend est appelé sur le pointeur nil; à la place, il renvoie une valeur (souvent utile). Les messages qui pourraient avoir un effet secondaire ne font rien.
C'est utile car la plupart des valeurs par défaut sont plus appropriées qu'une erreur. Par exemple:
Ie, nil semble être le tableau vide. Cacher une référence NSView nulle ne fait rien. Pratique, hein?
la source
Dans la citation de la documentation, il y a deux concepts distincts - il serait peut-être préférable que la documentation le précise plus clairement:
Le premier est probablement plus pertinent ici: le fait de pouvoir généralement envoyer des messages à
nil
rend le code plus simple - vous n'avez pas à vérifier les valeurs nulles partout. L'exemple canonique est probablement la méthode accesseur:Si l'envoi de messages à
nil
n'était pas valide, cette méthode serait plus complexe - vous devrez avoir deux vérifications supplémentaires pour vous assurervalue
etnewValue
ne le sont pasnil
avant de leur envoyer des messages.Le dernier point (les valeurs renvoyées par un message à
nil
sont également généralement valides), cependant, ajoute un effet multiplicateur au premier. Par exemple:Ce code ne nécessite pas de vérification des
nil
valeurs et s'écoule naturellement ...Cela dit, la flexibilité supplémentaire qui permet d'envoyer des messages a un
nil
certain coût. Il est possible que vous écriviez à un moment donné du code qui échoue d'une manière particulière parce que vous n'avez pas pris en compte la possibilité qu'une valeur puisse êtrenil
.la source
De Greg Parker de » site :
Si vous exécutez LLVM Compiler 3.0 (Xcode 4.2) ou version ultérieure
la source
Cela signifie souvent ne pas avoir à vérifier partout pour la sécurité aucun objet - en particulier:
ou, comme indiqué, diverses méthodes de comptage et de longueur renvoient toutes 0 lorsque vous avez une valeur nulle, vous n'avez donc pas à ajouter de vérifications supplémentaires pour nil partout:
ou ca:
la source
Ne pensez pas que "le récepteur est nul"; Je suis d' accord, c'est assez bizarre. Si vous envoyez un message à zéro, il n'y a pas de destinataire. Vous n'envoyez simplement un message à rien.
Comment gérer cela est une différence philosophique entre Java et Objective-C: en Java, c'est une erreur; en Objective-C, c'est un no-op.
la source
Les messages ObjC qui sont envoyés à nil et dont les valeurs de retour ont une taille supérieure à sizeof (void *) produisent des valeurs non définies sur les processeurs PowerPC. En plus de cela, ces messages provoquent le renvoi de valeurs non définies dans les champs des structures dont la taille est supérieure à 8 octets sur les processeurs Intel. Vincent Gable l'a bien décrit dans son article de blog
la source
Je ne pense pas qu'aucune des autres réponses l'ait mentionné clairement: si vous êtes habitué à Java, vous devez garder à l'esprit que si Objective-C sur Mac OS X prend en charge la gestion des exceptions, c'est une fonctionnalité de langage facultative qui peut être activé / désactivé avec un indicateur de compilateur. Je suppose que cette conception de «l'envoi de messages à
nil
est sûr» est antérieure à l'inclusion de la prise en charge de la gestion des exceptions dans le langage et a été réalisée avec un objectif similaire à l'esprit: les méthodes peuvent retournernil
pour indiquer des erreurs, et depuis l'envoi d'un message,nil
renvoie généralementnil
à son tour, cela permet à l'indication d'erreur de se propager dans votre code afin que vous n'ayez pas à la vérifier à chaque message. Vous n'avez qu'à le vérifier aux points où cela compte. Personnellement, je pense que la propagation et la gestion des exceptions sont un meilleur moyen d'atteindre cet objectif, mais tout le monde n'est pas d'accord avec cela. (D'un autre côté, par exemple, je n'aime pas l'exigence de Java selon laquelle vous devez déclarer les exceptions qu'une méthode peut lancer, ce qui vous oblige souvent à propager syntaxiquement des déclarations d'exception dans tout votre code; mais c'est une autre discussion.)J'ai posté une réponse similaire, mais plus longue, à la question connexe "Est-il nécessaire d'affirmer que chaque création d'objet a réussi en Objective C?" si vous voulez plus de détails.
la source
nil
retour souvent utilisé pour court-circuiter une chaîne en un NO-op.C ne représente rien comme 0 pour les valeurs primitives et NULL pour les pointeurs (ce qui équivaut à 0 dans un contexte de pointeur).
Objective-C s'appuie sur la représentation de rien par C en ajoutant nil. nil est un pointeur d'objet vers rien. Bien que sémantiquement distincts de NULL, ils sont techniquement équivalents les uns aux autres.
Les NSObjects nouvellement alloués démarrent avec leur contenu défini sur 0. Cela signifie que tous les pointeurs de cet objet vers d'autres objets commencent par nil, il est donc inutile, par exemple, de définir self. (Association) = nil dans les méthodes init.
Le comportement le plus notable de nil, cependant, est qu'il peut recevoir des messages.
Dans d'autres langages, comme C ++ (ou Java), cela planterait votre programme, mais en Objective-C, invoquer une méthode sur nil renvoie une valeur nulle. Cela simplifie considérablement les expressions, car cela évite d'avoir à vérifier nil avant de faire quoi que ce soit:
Être conscient de la façon dont nil fonctionne dans Objective-C permet à cette commodité d'être une fonctionnalité et non un bogue caché dans votre application. Assurez-vous de vous prémunir contre les cas où les valeurs nulles sont indésirables, soit en vérifiant et en retournant tôt pour échouer silencieusement, soit en ajoutant un NSParameterAssert pour lever une exception.
Source: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (Envoi d'un message à nil).
la source