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 he dicho esencialmente es: "no puedes hacerlo, pero aquí hay una aproximación cercana".
Hay una serie de palabras clave se aplica a ivars
(miembros) que controlan su ámbito de aplicación, por ejemplo @private
, @public
, @protected
. ¿Por qué no se puede hacer esto también por métodos? Parece algo que el tiempo de ejecución debería ser capaz de soportar. ¿Hay una filosofía subyacente que me falta? ¿Es esto deliberado?
objective-c
objective-c-runtime
Rob Jones
fuente
fuente
Respuestas:
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 pasa por el mismo punto de resolución de método dinámico que cualquier otro envío de método. 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 de la misma manera 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 disponible públicamente, entonces ese método podría no existir en lo que respecta a su código. En otras palabras, puede lograr todas las diversas combinaciones de visibilidad deseadas en el momento de la compilación organizando su proyecto adecuadamente.
Hay pocos beneficios al duplicar la misma funcionalidad en el tiempo de ejecución. Agregaría una enorme cantidad de complejidad y sobrecarga. E incluso con toda esa complejidad, todavía no evitaría que todos, excepto el desarrollador más informal, ejecuten sus métodos supuestamente "privados".
Sin embargo, hacerlo socavaría la naturaleza puramente dinámica del lenguaje. Ya no todos los envíos de métodos pasarían por un mecanismo de envío idéntico. En cambio, quedaría en una situación en la que la mayoría de los métodos se comportan de una manera y un pequeño puñado 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 constante de Objective-C. Por ejemplo, tanto la codificación del valor clave como la observación del valor clave tendrían que modificarse en gran medida para admitir métodos privados, muy probablemente creando una escapatoria explotable, o los métodos privados serían incompatibles.
fuente
El tiempo de ejecución podría soportarlo, pero el costo sería enorme. Debería comprobarse si cada selector que se envía 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 ejemplo 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 omitir los métodos privados; Si la clase se utiliza
instanceMethodForSelector:
, podría devolverIMP
a cualquier otra clase para que invoquen el método privado directamente.Los métodos privados no pudieron omitir el envío de mensajes. Considere el siguiente escenario:
Una clase
AllPublic
tiene un método de instancia públicadoSomething
Otra clase
HasPrivate
tiene un método de instancia privada también llamadodoSomething
Crea una matriz que contiene cualquier número de instancias de ambos
AllPublic
yHasPrivate
Tienes el siguiente bucle:
Si ejecutó ese ciclo desde adentro
AllPublic
, el tiempo de ejecución tendría que detener el envíodoSomething
de lasHasPrivate
instancias, sin embargo, este ciclo sería útil si estuviera dentro de laHasPrivate
clase.fuente
Las respuestas publicadas hasta ahora hacen un buen trabajo al responder la pregunta desde una perspectiva filosófica, por lo que voy a plantear una razón más pragmática: ¿qué se ganaría al cambiar la semántica del lenguaje? Es lo suficientemente simple como para "ocultar" efectivamente métodos privados. A modo de ejemplo, imagine que tiene una clase declarada en un archivo de encabezado, así:
Si necesita métodos "privados", también puede poner esto en el archivo de implementación:
Claro, no es exactamente lo mismo que los métodos privados de C ++ / Java, pero es lo suficientemente cerca, así que ¿por qué alterar la semántica del lenguaje, así como el compilador, el tiempo de ejecución, etc., para agregar una característica que ya está emulada de manera aceptable? ¿camino? Como se señaló en otras respuestas, la semántica de paso de mensajes, y su dependencia de la reflexión en tiempo de ejecución, haría que el manejo de mensajes "privados" no sea trivial.
fuente
La solución más fácil es declarar algunas funciones C estáticas en sus clases Objective-C. Estos solo tienen un alcance de archivo según las reglas C para la palabra clave estática y por eso solo pueden ser utilizados por métodos de esa clase.
Sin problemas en absoluto.
fuente
Sí, se puede hacer sin afectar el tiempo de ejecución utilizando una técnica ya empleada por el (los) compilador (es) para manejar C ++: cambio de nombre.
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., Prefijos o subrayados) son capaces de sortear suficientemente. IOW, necesitas más dolor para superar los hábitos arraigados.
Puede contribuir parches a clang o gcc que agreguen métodos privados a la sintaxis y generen nombres mutilados que solo él reconoció durante la compilación (y rápidamente olvidó). Luego, otros miembros de la comunidad de Objective-C podrían determinar si realmente valió la pena o no. Es probable que sea más rápido de esa manera que tratar de convencer a los desarrolladores.
fuente
Esencialmente, tiene que ver con la forma de paso de mensajes de Objective-C de llamadas a métodos. Cualquier mensaje puede enviarse 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 otras 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 los hace algo incómodos.
Incluso la implementación de métodos privados por parte de Ruby es un poco confusa para las personas debido a lo extraño (¡puede enviarle al objeto cualquier mensaje que desee, excepto los que están en esta lista !). Esencialmente, Ruby hace que funcione al prohibir que se llame 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.
fuente
Es un problema con el entorno de tiempo de ejecución de Objective-C. Si bien C / C ++ se compila en un código de máquina ilegible, Objective-C aún mantiene algunos atributos legibles por humanos, como los nombres de métodos como cadenas . Esto le da a Objective-C la capacidad de realizar características reflexivas .
EDITAR: Ser un lenguaje reflexivo sin métodos privados estrictos hace que Objective-C sea más "pitónico" en el sentido de que confía en otras personas que usan su código en lugar de restringir los métodos que pueden llamar. El uso de convenciones de nomenclatura como guiones bajos dobles tiene el objetivo de ocultar su código a un codificador de cliente informal, pero no detendrá a los codificadores que necesiten hacer un trabajo más serio.
fuente
Hay dos respuestas dependiendo de la interpretación de la pregunta.
La primera es ocultar la implementación del método de la interfaz. Esto se usa, típicamente con una categoría sin nombre (por ejemplo
@interface Foo()
). Esto permite que el objeto envíe esos mensajes pero no otros, aunque uno podría anular accidentalmente (o de otro modo).La segunda respuesta, en el supuesto de que se trata de rendimiento e inline, es posible, pero como una función C local. Si quieres un 'foo privada (
NSString *arg
)' método, que haríavoid MyClass_foo(MyClass *self, NSString *arg)
y lo llaman como una función de C comoMyClass_foo(self,arg)
. La sintaxis es diferente, pero actúa con el tipo de características de rendimiento sensatas 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 hacer esto.
fuente
Objective-C no admite métodos privados porque no los necesita.
En C ++, cada método debe ser visible en la declaración de la clase. No puede tener métodos que alguien que incluya el archivo de encabezado no pueda ver. Entonces, si desea métodos que el código fuera de su implementación no debería usar, no tiene otra opción, el compilador debe darle alguna herramienta para que pueda decirle que el método no debe usarse, esa es la palabra clave "privada".
En Objective-C, puede tener métodos que no están en el archivo de encabezado. Entonces 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 cada usuario de una clase porque cambió los métodos privados.
Por ejemplo, las variables que solía declarar en el archivo de encabezado (ya no están disponibles), @private, @public y @protected están disponibles.
fuente
Una respuesta que falta aquí es: porque los métodos privados son una mala idea desde el punto de vista de la evolución. Puede parecer una buena idea hacer que un método sea privado al escribirlo, pero es una forma de enlace temprano. 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 asumimos la responsabilidad de lidiar con las consecuencias si necesitamos cambiar la implementación. Entonces sí, es filosofía, no implementación.
fuente