Como desarrollador de Java que está leyendo la documentación de 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 de 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 que sizeof (void *), un flotante, un doble, un doble largo o un largo largo, entonces un mensaje enviado a nil devuelve 0 .
- Si el método devuelve una estructura, según lo definido por la Guía de llamadas a funciones ABI de Mac OS X para que se devuelva en los registros, un mensaje enviado a nil devuelve 0.0 para cada campo en la estructura de datos. Otros tipos de datos de estructura no se rellenarán con ceros.
- Si el método devuelve algo diferente a los tipos de valor mencionados anteriormente, el valor de retorno de un mensaje enviado a nil 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 lo dejaría tan claro como el vidrio?
Tengo la idea de mensajes / receptores en Objective-C, simplemente estoy confundido acerca de un receptor que resulta ser nil
.
objective-c
Ryan Delucchi
fuente
fuente
Respuestas:
Bueno, creo que se puede describir con un ejemplo muy elaborado. Digamos que tiene un método en Java que imprime todos los elementos en una ArrayList:
Ahora, si llama 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 así. 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:
Ahora, en Objective-C, tenemos el método equivalente:
Ahora, si tenemos el siguiente código:
tenemos la misma situación en la que Java producirá una NullPointerException. Se accederá primero al objeto nil en [anArray count] Sin embargo, en lugar de lanzar 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 dado que objectAtIndex: devuelve un puntero, y un puntero a 0 es nil / NULL, NSLog pasará nil cada vez a través del 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 NullPointerException, ya que puede saber de inmediato que algo anda mal con el programa, pero a menos que detecte la excepción, el programa se bloqueará. (En C, intentar eliminar la referencia a NULL de esta manera hace que el programa se bloquee). En Objective-C, en cambio, solo causa un comportamiento de tiempo de ejecución posiblemente incorrecto. Sin embargo, si tiene un método que no se rompe si devuelve 0 / nil / NULL / una estructura cero, esto le evita tener que verificar para asegurarse de que el objeto o los parámetros sean nulos.
fuente
myObject->iVar
se bloqueará, independientemente de si es C con o sin objetos. (perdón por->
ya no es una operación de Objective-C sino más bien un C-ismo genérico.Un mensaje que
nil
no hace nada y vuelvenil
,Nil
,NULL
,0
, o0.0
.fuente
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 destino válido para ese selector.
Esto ahorra MUCHO "¿el objeto de destino es de tipo X?" código: siempre que el objeto receptor implemente el selector, ¡ no importa qué clase sea!
nil
es un NSObject que acepta cualquier selector, simplemente no hace nada. Esto elimina una gran cantidad de código de "verificación nula, no envíe el mensaje si es verdadero" también. (El concepto "si lo acepta, lo implementa" es también 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 establecidos, 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í, obtiene la sobrecarga de una llamada más al método, pero ahorra tiempo al programador , que es un recurso mucho más caro que el tiempo de la CPU. Además, está eliminando más código y más complejidad condicional de su aplicación.
Aclaración para los votantes negativos: puede 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).
fuente
Lo que significa es que el tiempo de ejecución no produce un error cuando se llama a objc_msgSend en el puntero nulo; en su lugar, devuelve algún valor (a menudo útil). Los mensajes que pueden tener un efecto secundario no hacen nada.
Es útil porque la mayoría de los valores predeterminados son más apropiados que un error. Por ejemplo:
Es decir, nil parece ser la matriz vacía. Ocultar una referencia nula de NSView no hace nada. Práctico, ¿eh?
fuente
En la cita de la documentación, hay dos conceptos separados; tal vez sería mejor si la documentación lo dejara más claro:
Lo primero es probablemente más relevante aquí: por lo general, poder enviar mensajes a
nil
hace que el código sea más sencillo; no tiene que buscar valores nulos en todas partes. El ejemplo canónico es probablemente el método de acceso:Si enviar mensajes a
nil
no fuera válido, este método sería más complejo: tendría que tener dos comprobaciones adicionales para asegurarsevalue
ynewValue
nonil
antes de enviarles mensajes.Sin
nil
embargo, el último punto (al que los valores devueltos por un mensaje también suelen ser válidos) agrega un efecto multiplicador al primero. Por ejemplo:Este código nuevamente no requiere una verificación de
nil
valores y fluye naturalmente ...Dicho todo esto, la flexibilidad adicional a la que poder enviar mensajes
nil
tiene algún costo. Existe la posibilidad de que en algún momento escriba un código que falle de una manera peculiar porque no tuvo en cuenta la posibilidad de que un valor pudiera sernil
.fuente
De Greg Parker 's sitio :
Si ejecuta LLVM Compiler 3.0 (Xcode 4.2) o posterior
fuente
A menudo significa no tener que buscar ningún objeto en todas partes por seguridad, en particular:
o, como se señaló, varios métodos de conteo y longitud devuelven 0 cuando tiene un valor nulo, por lo que no tiene que agregar comprobaciones adicionales para nulo:
o esto:
fuente
No piense en "el receptor es nulo"; Estoy de acuerdo, eso es bastante extraño. Si envía un mensaje a cero, no hay receptor. Estás enviando un mensaje a la nada.
Cómo lidiar con eso es una diferencia filosófica entre Java y Objective-C: en Java, eso es un error; en Objective-C, no es una operación.
fuente
Los mensajes ObjC que se envían a cero y cuyos valores de retorno tienen un tamaño mayor que sizeof (void *) producen valores indefinidos en los procesadores PowerPC. Además de eso, estos mensajes hacen que se devuelvan valores indefinidos en campos de estructuras cuyo tamaño sea mayor de 8 bytes en procesadores Intel también. Vincent Gable ha descrito esto muy bien en su publicación de blog.
fuente
No creo que ninguna de las otras respuestas haya mencionado esto claramente: si está acostumbrado a Java, debe tener en cuenta que, si bien Objective-C en Mac OS X tiene soporte para manejo de excepciones, es una característica de lenguaje opcional que puede ser encendido / apagado con un indicador de compilador. Supongo que este diseño de "enviar mensajes a
nil
es seguro" es anterior a la inclusión del soporte de manejo de excepciones en el idioma y se hizo con un objetivo similar en mente: los métodos pueden regresarnil
para indicar errores y, dado que enviar un mensaje a,nil
generalmente regresanil
a su vez, esto permite que la indicación de error se propague a través de su código para que no tenga que buscarlo en cada mensaje. Solo tiene que verificarlo en los puntos donde sea importante. Personalmente, creo que la propagación y el manejo de excepciones es una mejor manera de abordar este objetivo, pero no todos pueden estar de acuerdo con eso. (Por otro lado, por ejemplo, no me gusta el requisito de Java de que tengas que declarar qué excepciones puede arrojar un método, lo que a menudo te obliga a propagar sintácticamente declaraciones de excepción a lo largo de tu código; pero esa es otra discusión).Publiqué una respuesta similar, pero más larga, a la pregunta relacionada "¿Es necesario afirmar que cada creación de objetos tuvo éxito en el Objetivo C?" si quieres más detalles.
fuente
nil
usaba un retorno para cortocircuitar una cadena en una operación NO.C no representa nada como 0 para valores primitivos y NULL para punteros (que es equivalente a 0 en un contexto de puntero).
Objective-C se basa en la representación de C de nada agregando nil. nil es un puntero de objeto a nada. Aunque semánticamente distintos de NULL, son técnicamente equivalentes entre sí.
Los NSObjects recién asignados comienzan su vida con su contenido establecido en 0. Esto significa que todos los punteros que el objeto tiene a otros objetos comienzan como nil, por lo que no es necesario, por ejemplo, establecer self. (Association) = nil en los métodos init.
Sin embargo, el comportamiento más notable de nil es que puede recibir mensajes.
En otros lenguajes, como C ++ (o Java), esto bloquearía su programa, pero en Objective-C, invocar un método en nil devuelve un valor cero. Esto simplifica enormemente las expresiones, ya que evita la necesidad de verificar nil antes de hacer algo:
Ser consciente de cómo funciona nil en Objective-C permite que esta conveniencia sea una característica y no un error al acecho en su aplicación. Asegúrese de protegerse contra los casos en los que los valores nulos no sean deseados, ya sea verificando y regresando temprano para fallar silenciosamente o agregando un NSParameterAssert para lanzar una excepción.
Fuente: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (Enviar mensaje a nil).
fuente