Enviar un mensaje a cero en Objective-C

Resuelto Ryan Delucchi asked hace 16 años • 11 respuestas

Como desarrollador de Java que está leyendo la documentación Objective-C 2.0 de Apple: me pregunto qué significa " enviar un mensaje a cero ", y mucho menos cómo es realmente útil. Tomando un extracto de la documentación:

Hay varios patrones en Cocoa que aprovechan este hecho. El valor devuelto por un mensaje a nil también puede ser válido:

  • Si el método devuelve un objeto, cualquier tipo de puntero, cualquier escalar entero de tamaño menor o igual a sizeof(void*), un float, un double, un long double o un long long, entonces un mensaje enviado a nil devuelve 0 .
  • Si el método devuelve una estructura, tal como se define en la Guía de llamadas a funciones ABI de Mac OS X, que se devolverá en los registros, entonces un mensaje enviado a nil devuelve 0,0 para cada campo de la estructura de datos. Otros tipos de datos de estructura no se completarán con ceros.
  • Si el método devuelve algo distinto de los tipos de valores antes mencionados, el valor de retorno de un mensaje enviado a cero no está definido.

¿Java ha hecho que mi cerebro sea incapaz de asimilar la explicación anterior? ¿O hay algo que me falta y que haría que esto fuera tan claro como el cristal?

Entiendo la idea de mensajes/receptores en Objective-C, simplemente estoy confundido acerca de un receptor que resulta ser nil.

Ryan Delucchi avatar Oct 01 '08 13:10 Ryan Delucchi
Aceptado

Bueno, creo que se puede describir usando un ejemplo muy artificial. Digamos que tienes un método en Java que imprime todos los elementos en una ArrayList:

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

Ahora, si llamas a ese método así: someObject.foo(NULL); probablemente obtendrá una NullPointerException cuando intente acceder a la lista, en este caso en la llamada a list.size(); Ahora, probablemente nunca llamarías a someObject.foo(NULL) con el valor NULL de esa manera. Sin embargo, es posible que haya obtenido su ArrayList de un método que devuelve NULL si se encuentra con algún error al generar ArrayList como someObject.foo(otherObject.getArrayList());

Por supuesto, también tendrás problemas si haces algo como esto:

ArrayList list = NULL;
list.size();

Ahora, en Objective-C, tenemos el método equivalente:

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

Ahora, si tenemos el siguiente código:

[someObject foo:nil];

Tenemos la misma situación en la que Java producirá una NullPointerException. Se accederá primero al objeto nulo en [anArray count]. Sin embargo, en lugar de generar una NullPointerException, Objective-C simplemente devolverá 0 de acuerdo con las reglas anteriores, por lo que el bucle no se ejecutará. Sin embargo, si configuramos el bucle para que se ejecute un número determinado de veces, primero enviaremos un mensaje a anArray en [anArray objectAtIndex:i]; Esto también devolverá 0, pero como objectAtIndex: devuelve un puntero, y un puntero a 0 es nulo/NULL, NSLog pasará a cero cada vez que pase por el bucle. (Aunque NSLog es una función y no un método, se imprime (nulo) si se le pasa un NSString nulo.

En algunos casos es mejor tener una excepción NullPointerException, ya que puedes saber inmediatamente que algo anda mal con el programa, pero a menos que detectes la excepción, el programa fallará. (En C, intentar eliminar la referencia a NULL de esta manera hace que el programa se bloquee). En Objective-C, en cambio, solo provoca un comportamiento posiblemente incorrecto en tiempo de ejecución. Sin embargo, si tiene un método que no se rompe si devuelve 0/nil/NULL/una estructura puesta a cero, esto le evita tener que verificar para asegurarse de que el objeto o los parámetros sean nulos.

Michael Buckley avatar Oct 01 '2008 06:10 Michael Buckley

Un mensaje para nilno hace nada y devuelve nil, Nil, NULL, 0o 0.0.

Peter Hosey avatar Nov 10 '2008 02:11 Peter Hosey

Todas las demás publicaciones son correctas, pero tal vez sea el concepto lo importante aquí.

En las llamadas al método Objective-C, cualquier referencia de objeto que pueda aceptar un selector es un objetivo válido para ese selector.

Esto ahorra MUCHAS preguntas "¿el objeto de destino es de tipo X?" código: siempre que el objeto receptor implemente el selector, ¡ no importa en absoluto qué clase sea! niles un NSObject que acepta cualquier selector, simplemente no hace nada. Esto también elimina una gran cantidad de código de "comprobar si es nulo, no enviar el mensaje si es verdadero". (El concepto "si lo acepta, lo implementa" también es lo que le permite crear protocolos , que son algo así como interfaces Java: una declaración de que si una clase implementa los métodos indicados, entonces se ajusta al protocolo).

La razón de esto es eliminar el código mono que no hace nada más que mantener contento al compilador. Sí, obtienes la sobrecarga de una llamada de método más, pero ahorras tiempo al programador , que es un recurso mucho más costoso que el tiempo de CPU. Además, está eliminando más código y más complejidad condicional de su aplicación.

Aclarando a los votantes negativos: pueden pensar que este no es un buen camino a seguir, pero así es como se implementa el lenguaje, y es el lenguaje de programación recomendado en Objective-C (consulte las conferencias de programación de iPhone de Stanford).

Joe McMahon avatar Nov 21 '2008 21:11 Joe McMahon