106 votes

Envoyer un message à nil?

En tant que développeur Java qui est de la lecture de Apple Objective-C 2.0 documentation: je me demande ce que l'envoi d'un message à néant les moyens - et encore moins comment il est réellement utile. La prise d'un extrait de la documentation:

Il y a plusieurs modèles dans le Cacao que tirer parti de ce fait. L' la valeur de retour à partir d'un message à néant peuvent également être valables:

  • Si la méthode retourne un objet, d'un type pointeur, tout entier scalaire de taille inférieure ou égale à sizeof(void*), d'un flotteur, d'un lit double, une long double, ou un long, puis un message envoyé à néant retourne 0.
  • Si la méthode renvoie une structure, telle que définie par le système Mac OS X ABI Fonction Appel Guide pour être retourné dans registres, puis un message envoyé à néant retourne 0.0 pour chaque champ dans la structure de données. Autre structure de données les types ne sera pas rempli avec des zéros.
  • Si la méthode renvoie autre chose que celle de ladite valeur les types de la valeur de retour d'un message envoyé à zéro n'est pas défini.

A Java rendu à mon cerveau incapable de grokking l'explication ci-dessus? Ou est-il quelque chose que je suis manquant qui permettrait de faire de ce clair comme du verre?

Note: Oui, je comprends l'idée de messages/récepteurs en Objective-C, je suis simplement confus au sujet d'un récepteur qui se trouve être nul.

92voto

Michael Buckley Points 2856

Eh bien, je pense qu'il peut être décrit à l'aide d'un très artificiel exemple. Disons que vous avez une méthode en Java qui permet d'afficher tous les éléments dans une liste de tableaux:

void foo(ArrayList list)
{
    for(int i = 0; i < list.size(); ++i){
        System.out.println(list.get(i).toString());
    }
}

Maintenant, si vous appelez la méthode comme suit: someObject.foo(NULL); vous allez probablement obtenir un NullPointerException lorsqu'il tente d'accéder à la liste, dans ce cas, l'appel à la liste.size(); Maintenant, vous pensez probablement jamais appel someObject.foo(NULL) avec la valeur NULL comme ça. Cependant, vous avez obtenu votre liste de tableaux à partir d'une méthode qui retourne la valeur NULL s'il s'agit d'une erreur de générer la liste de tableaux comme someObject.foo(otherObject.getArrayList());

Bien sûr, vous aurez des problèmes si vous faites quelque chose comme cela:

ArrayList list = NULL;
list.size();

Maintenant, en Objective-C, nous avons l'équivalent de la méthode:

- (void)foo:(NSArray*)anArray
{
    int i;
    for(i = 0; i < [anArray count]; ++i){
        NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
    }
}

Maintenant, si nous avons le code suivant:

[someObject foo:nil];

nous avons la même situation en Java qui va produire une NullPointerException. Le néant, l'objet sera tout d'abord accéder à [anArray count] Cependant, au lieu de lancer une exception NullPointerException, Objective-C, il suffit de le retourner 0 en conformité avec les règles ci-dessus, de sorte que la boucle ne s'exécute pas. Cependant, si nous mettons de la boucle pour exécuter un certain nombre de fois, alors que nous sommes d'abord l'envoi d'un message à anArray à [anArray objectAtIndex:i]; C'est également de retour 0, mais depuis objectAtIndex: retourne un pointeur, et un pointeur vers 0 est nul/NULLE, NSLog sera passé néant chaque passage dans la boucle. (Bien que NSLog est une fonction et non pas une méthode, il imprime (null) si elle est transmise d'un néant NSString.

Dans certains cas, il est plus agréable d'avoir une NullPointerException, puisque vous pouvez le dire tout de suite que quelque chose est incorrect avec le programme, mais à moins d'intercepter l'exception, le programme plantera. (En C, en essayant de déréférencer NULL de cette façon, le programme crash.) En Objective-C, au lieu des causes justes, peut-être inexacte au moment de l'exécution de comportement. Toutefois, si vous avez une méthode qui ne se casse pas si elle retourne 0/nul/NULLE/une mise à zéro de struct, alors cela vous évite d'avoir à vérifier pour s'assurer que l'objet ou les paramètres sont nuls.

51voto

Peter Hosey Points 66275

Un message à nil ne fait rien et retourne nil , Nil , NULL , 0 , ou 0.0 .

41voto

Joe McMahon Points 1345

Tous les autres postes sont corrects, mais c'est peut-être le concept qui est la chose importante ici.

En Objective-C les appels de méthode, d'un objet de référence qui peut accepter un sélecteur est une cible valide pour que le sélecteur.

Cela permet d'économiser BEAUCOUP de "il est la cible de l'objet de type X?" code - tant que la réception de l'objet met en œuvre le sélecteur, il fait absolument aucune différence dans quelle classe il est! nil est un NSObject qui accepte n'importe quel sélecteur - elle juste ne pas faire n'importe quoi. Ceci élimine beaucoup de "vérifier néant, n'envoyez pas le message si vrai" code ainsi. ("Si elle accepte, elle met en œuvre ce concept est aussi ce qui permet de créer des protocoles, qui sont sorta un peu comme Java interfaces: une déclaration que si une classe implémente les méthodes établies, alors qu'il se conforme au protocole.)

La raison pour cela est d'éliminer singe code qui ne fait rien, sauf de garder le compilateur heureux. Oui, vous obtenez les frais généraux d'un appel de méthode, mais vous économisez le temps du programmeur, ce qui est beaucoup plus coûteux en ressources que le temps CPU. En outre, vous êtes en éliminant plus de code et plus de conditionnel de la complexité de votre application.

17voto

Rich Points 2429

Cela signifie que l'exécution ne génère pas d'erreur lorsque objc_msgSend est appelé sur le pointeur nil. à la place, il renvoie une valeur (souvent utile). Les messages susceptibles d'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:

 [someNullNSArrayReference count] => 0
 

C'est-à-dire que rien ne semble être le tableau vide. Masquer une référence NSView nulle ne fait rien. Pratique, hein?

12voto

mmalc Points 7663

Dans la citation de la documentation, il y a deux concepts distincts, peut-être il pourrait être mieux si la documentation fait que de plus en plus clair:

Il y a plusieurs modèles dans le Cacao, qui profitent de cet état de fait.

La valeur renvoyée par un message à zéro peuvent également être valables:

Le premier est probablement plus pertinent ici: généralement être en mesure d'envoyer des messages à d' nil rend le code plus simple, vous n'avez pas à vérifier les valeurs null partout. L'exemple canonique est probablement la méthode d'accesseur:

- (void)setValue:(MyClass *)newValue {
    if (value != newValue) { 
        [value release];
        value = [newValue retain];
    }
}

Si l'envoi de messages à l' nil n'étaient pas valides, cette méthode serait plus complexe, vous auriez à deux autres contrôles pour garantir value et newValue ne sont pas nil avant l'envoi des messages.

Le dernier point que les valeurs de retour d'un message d' nil sont également valables), mais, ajoute un effet multiplicateur à l'ancienne. Par exemple:

if ([myArray count] > 0) {
    // do something...
}

Ce code ne nécessite pas un contrôle pour l' nil valeurs, et coule naturellement...

Tout cela dit, l'augmentation de la souplesse que le fait de pouvoir envoyer des messages à d' nil ne viennent à un certain coût. Il est possible que vous allez à un certain stade de l'écriture du code qui échoue dans une manière très particulière parce que vous ne pas tenir compte de la possibilité qu'une valeur peut être nil.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X