origen objective idioma funciona estructura entorno desarrollo como caracteristicas objective-c objective-c-runtime

objective-c - idioma - origen de objective c



¿Por qué Objective-C no admite métodos privados? (10)

He visto una serie de estrategias para declarar métodos semiprivados en Objective-C , pero no parece haber una manera de hacer un método verdaderamente privado. Yo acepto que. ¿Pero por qué es esto así? Cada explicación que esencialmente dice, "no puedes hacerlo, pero aquí hay una aproximación cercana".

Hay varias palabras clave aplicadas a ivars (miembros) que controlan su alcance, por ejemplo, @public , @protected , @protected . ¿Por qué no se puede hacer esto también para los métodos? Parece algo que el tiempo de ejecución debería ser capaz de soportar. ¿Hay una filosofía subyacente que me falta? ¿Esto es deliberado?


Básicamente, tiene que ver con la forma de paso de mensajes de método de Objective-C. Se puede enviar cualquier mensaje a cualquier objeto, y el objeto elige cómo responder al mensaje. Normalmente responderá ejecutando el método nombrado después del mensaje, pero también podría responder de varias maneras. Esto no hace que los métodos privados sean completamente imposibles, Ruby lo hace con un sistema similar de transmisión de mensajes, pero sí los torna algo incómodos.

Incluso la implementación de métodos privados de Ruby es un poco confusa para las personas debido a la extrañeza (¡puede enviar al objeto cualquier mensaje que desee, excepto los de esta lista !). Básicamente, Ruby funciona al prohibir que se llamen a métodos privados con un receptor explícito. En Objective-C requeriría aún más trabajo ya que Objective-C no tiene esa opción.


El tiempo de ejecución podría soportarlo, pero el costo sería enorme. Cada selector que se envíe deberá verificarse para ver si es privado o público para esa clase, o cada clase necesitaría administrar dos tablas de despacho separadas. Esto no es lo mismo para las variables de instancia porque este nivel de protección se realiza en tiempo de compilación.

Además, el tiempo de ejecución necesitaría verificar que el remitente de un mensaje privado sea de la misma clase que el receptor. También puede pasar por alto los métodos privados; si la clase utiliza instanceMethodForSelector: podría dar el IMP devuelto a cualquier otra clase para que invoque directamente el método privado.

Los métodos privados no pueden omitir el envío del mensaje. Considere la siguiente situación:

  1. Una clase AllPublic tiene un método de instancia pública doSomething

  2. Otra clase HasPrivate tiene un método de instancia privado también llamado doSomething

  3. Usted crea una matriz que contiene cualquier cantidad de instancias de AllPublic y HasPrivate

  4. Usted tiene el siguiente ciclo:

    for (id anObject in myArray) [anObject doSomething];

    Si ejecutó ese bucle desde AllPublic , el tiempo de ejecución tendría que evitar que envíe HasPrivate instancias de HasPrivate ; sin embargo, este bucle sería utilizable si estuviera dentro de la clase HasPrivate .


Es un problema con el entorno de tiempo de ejecución de Objective-C. Mientras C / C ++ se compila en código de máquina ilegible, Objective-C aún mantiene algunos atributos legibles por el ser humano, como los nombres de los métodos, como cadenas . Esto le da a Objective-C la capacidad de realizar funciones de reflective .

EDITAR: Ser un lenguaje reflexivo sin estrictos métodos privados hace que Objective-C sea más "pitónico" en cuanto a que confías en otras personas que usan tu código en lugar de restringir los métodos a los que pueden llamar. El uso de convenciones de nomenclatura como guiones bajos dobles tiene como objetivo ocultar el código de un codificador de cliente ocasional, pero no impedirá que los codificadores necesiten realizar un trabajo más serio.


Hay dos respuestas dependiendo de la interpretación de la pregunta.

El primero es ocultar la implementación del método desde la interfaz. Esto se usa, generalmente con una categoría sin nombre (por ejemplo, @interface Foo() ). Esto permite que el objeto envíe esos mensajes pero no otros, aunque aún se puede anular accidentalmente (o de lo contrario).

La segunda respuesta, en el supuesto de que esto se trata de rendimiento y alineación, es posible, pero en su lugar como una función C local. Si quisiera un método ''private foo ( NSString *arg )'', void MyClass_foo(MyClass *self, NSString *arg) y lo llamaría como una función C como MyClass_foo(self,arg) . La sintaxis es diferente, pero actúa con el mismo tipo de características de rendimiento de los métodos privados de C ++.

Aunque esto responde a la pregunta, debo señalar que la categoría sin nombre es, con mucho, la forma más común de Objective-C de hacer esto.


La respuesta es ... bueno ... simple. Simplicidad y consistencia, de hecho.

Objective-C es puramente dinámico en el momento del envío del método. En particular, cada envío de método atraviesa exactamente el mismo punto de resolución de método dinámico que cualquier otro método de envío. En tiempo de ejecución, cada implementación de método tiene exactamente la misma exposición y todas las API proporcionadas por el tiempo de ejecución de Objective-C que funcionan con métodos y selectores funcionan igual en todos los métodos.

Como muchos han respondido (tanto aquí como en otras preguntas), se admiten métodos privados en tiempo de compilación; si una clase no declara un método en su interfaz de acceso público, entonces ese método tampoco podría existir en lo que respecta a su código. En otras palabras, puede lograr todas las diversas combinaciones de visibilidad deseadas en tiempo de compilación organizando su proyecto adecuadamente.

Hay poco beneficio de duplicar la misma funcionalidad en el tiempo de ejecución. Agregaría una enorme cantidad de complejidad y gastos generales. E incluso con toda esa complejidad, no impediría que todos, excepto el desarrollador más casual, ejecutaran sus métodos supuestamente "privados".

EDITAR: Una de las suposiciones que he notado es que los mensajes privados tendrían que pasar por el tiempo de ejecución, lo que daría lugar a una sobrecarga potencialmente grande. ¿Es esto absolutamente cierto?

Sí lo es. No hay ninguna razón para suponer que el implementador de una clase no quiera utilizar todas las características de Objective-C establecidas en la implementación, y eso significa que el despacho dinámico debe ocurrir. Sin embargo , no hay una razón particular por la que los métodos privados no puedan ser enviados por una variante especial de objc_msgSend() , ya que el compilador sabría que eran privados; es decir, esto podría lograrse agregando una tabla de métodos privados solamente a la estructura de la Class .

No habría forma de que un método privado cortocircuite esta comprobación u omita el tiempo de ejecución.

No podía omitir el tiempo de ejecución, pero el tiempo de ejecución no necesariamente tendría que comprobar los métodos privados.

Dicho esto, no hay ninguna razón para que un tercero no llame deliberadamente a objc_msgSendPrivate() en un objeto, fuera de la implementación de ese objeto, y algunas cosas (KVO, por ejemplo) tendrían que hacer eso. De hecho, sería simplemente una convención y un poco mejor en la práctica que el prefijo de los selectores de métodos privados o no mencionarlos en el encabezado de la interfaz.

Hacerlo, sin embargo, socavaría la naturaleza dinámica pura del lenguaje. Ya no todos los métodos de envío pasan por un mecanismo de envío idéntico. En cambio, te quedarías en una situación en la que la mayoría de los métodos se comportan de una manera y un puñado pequeño son simplemente diferentes.

Esto se extiende más allá del tiempo de ejecución ya que hay muchos mecanismos en Cocoa construidos sobre el dinamismo consistente de Objective-C. Por ejemplo, tanto la Codificación del valor clave como la Observación del valor clave deberían modificarse en gran medida para admitir métodos privados, probablemente mediante la creación de una laguna explotable, o los métodos privados serían incompatibles.


La solución más fácil es simplemente declarar algunas funciones C estáticas en sus clases Objective-C. Solo tienen alcance de archivo según las reglas de C para la palabra clave estática y, por lo tanto, solo pueden ser utilizados por los métodos de esa clase.

Sin problemas en absoluto.


Las respuestas publicadas hasta ahora hacen un buen trabajo respondiendo la pregunta desde una perspectiva filosófica, así que voy a postular una razón más pragmática: ¿qué se ganaría cambiando la semántica del lenguaje? Es lo suficientemente simple como para "ocultar" métodos privados de forma efectiva. A modo de ejemplo, imagina que tienes una clase declarada en un archivo de encabezado, así:

@interface MyObject : NSObject {} - (void) doSomething; @end

Si necesita métodos "privados", también puede poner esto en el archivo de implementación:

@interface MyObject (Private) - (void) doSomeHelperThing; @end @implementation MyObject - (void) doSomething { // Do some stuff [self doSomeHelperThing]; // Do some other stuff; } - (void) doSomeHelperThing { // Do some helper stuff } @end

Claro, no es lo mismo que los métodos privados de C ++ / Java, pero es efectivamente lo suficientemente cerca, ¿por qué alterar la semántica del lenguaje, así como el compilador, el tiempo de ejecución, etc., para agregar una función que ya está emulada en un aceptable ¿camino? Como se señaló en otras respuestas, la semántica de transmisión de mensajes y su confianza en la reflexión del tiempo de ejecución harían que el manejo de mensajes "privados" no fuera trivial.


Objective-C no es compatible con métodos privados porque no los necesita.

En C ++, todos los métodos deben ser visibles en la declaración de la clase. No puede tener métodos que alguien que incluye el archivo de encabezado no pueda ver. Entonces, si quiere que los métodos que el código fuera de su implementación no deberían usar, no tiene otra opción, el compilador debe darle alguna herramienta para que pueda decirle que el método no debe ser usado, que es la palabra clave "privada".

En Objective-C, puede tener métodos que no están en el archivo de encabezado. Por lo tanto, logra el mismo propósito muy fácilmente al no agregar el método al archivo de encabezado. No hay necesidad de métodos privados. Objective-C también tiene la ventaja de que no necesita recompilar a todos los usuarios de una clase porque cambió los métodos privados.

Por ejemplo, las variables que solía declarar en el archivo de encabezado (ya no), @private, @public y @protected están disponibles.


Sí, se puede hacer sin afectar el tiempo de ejecución al utilizar una técnica ya empleada por el compilador (es) para manejar C ++: name-mangling.

No se ha hecho porque no se ha establecido que resolvería una dificultad considerable en el espacio del problema de codificación que otras técnicas (p. Ej., Prefijación o subrayado) pueden eludir suficientemente. IOW, necesitas más dolor para superar los hábitos arraigados.

Podría contribuir parches para clang o gcc que agreguen métodos privados a la sintaxis y generen nombres destrozados que solo ellos reconocieron durante la compilación (y lo olvidó de inmediato). Luego, otros en la comunidad de Objective-C podrían determinar si realmente valía la pena o no. Es probable que sea más rápido de esa manera que tratando de convencer a los desarrolladores.


Una respuesta que falta aquí es: porque los métodos privados son una mala idea desde el punto de vista de la capacidad de evolución. Puede parecer una buena idea hacer que un método sea privado al escribirlo, pero es una forma de enlace anticipado. El contexto puede cambiar, y un usuario posterior puede querer usar una implementación diferente. Un poco provocativo: "Los desarrolladores ágiles no usan métodos privados"

En cierto modo, al igual que Smalltalk, Objective-C es para programadores adultos. Valoramos saber lo que el desarrollador original asumió que debería ser la interfaz, y tomamos la responsabilidad de lidiar con las consecuencias si necesitamos cambiar la implementación. Entonces sí, es filosofía, no implementación.