variable mostrar mega inicializar conexion conectar comandos codigo 2x16 20x4 16x2 objective-c initialization subclass superclass

objective c - mostrar - ¿Por qué las subclases de inicialización requieren llamar a la misma función init de la superclase?



lcd arduino i2c (5)

He oído que cuando tienes una subclase, se supone que debes inicializar la superclase con la misma función init desde el init de la subclase. Lo que quiero decir es que el init de la subclase debe llamar a [superinicio] y initWithFrame de la subclase debe llamar a [superinicioWithFrame]. ¿Por qué es esto? ¿Por qué llamar a la inicial del super desde el initWithFrame de una subclase resulta en un bucle infinito?

Si esto es necesario, ¿significa esto que no puedo crear una nueva función init dentro de una subclase como initWithPoint y tener esa llamada super init o initWithFrame simplemente porque la superclase no tiene initWithPoint? Supongo que el corazón de la pregunta aquí es simplemente por qué es incorrecto llamar a una súper clase diferente, algo que me confunde posiblemente debido a mi experiencia en c ++.


¿Por qué es esto? ¿Por qué llamar a la inicial del super desde el initWithFrame de una subclase resulta en un bucle infinito?

Si el -init en super se implementa como

-(id)init { return [self initWithFrame:CGRectZero]; }

entonces el gráfico de llamadas recorrerá:

[subclass initWithFrame:] | ^ v | [super init]

como self siempre uso la clase actual ("subclase").

Si esto es necesario, ¿significa esto que no puedo crear una nueva función init dentro de una subclase como initWithPoint y tener esa llamada super init o initWithFrame simplemente porque la superclase no tiene initWithPoint?

No, esto no es obligatorio. Lo que se prefiere es llamar al inicializador más especializado de super , por lo que no hay ninguna posibilidad de que super -initXXX devuelva la llamada a la subclase -initYYY .


¿Por qué llamar a la inicial del super desde el initWithFrame de una subclase resulta en un bucle infinito?

Viniendo de un fondo de C ++ como dices, el problema principal es probablemente que estés acostumbrado al paradigma de llamadas al método C ++. En Objective-C, no llamas funciones de objetos. Ni siquiera es técnicamente correcto decir que invocas métodos. En Objective-C, envía mensajes a objetos y el objeto decide qué hacer con ellos. Lo que normalmente hace es buscar un método en su clase e invocarlo. La consecuencia de esto es que no puede controlar qué versión de un método en una jerarquía de clases obtiene invocada por un mensaje. Siempre es el método que pertenece a la clase del objeto al que envía el mensaje (excepto en un caso). Es como si C ++ no tuviera funciones no virtuales, ni siquiera los constructores.

La única excepción a esto es cuando envía un mensaje a super. En ese caso, el método en su clase es pasado por alto. Esto puede conducir a bucles infinitos, como habrás descubierto. La razón es porque no llamamos a funciones, enviamos mensajes. Entonces, si el método A de la clase SubKlass envía [super methodB] la implementación del método B en Klass. Si luego envía [self methodA] self aún es una instancia de SubKlass, no se ha transformado mágicamente en una instancia de Klass, por lo que se invocará el método A en SubKlass.

Esta es la razón por la cual las reglas para los inicializadores parecen ser tan intrincadas. Solo se garantiza que el inicializador designado no enviará uno de los otros inicializadores, por lo que solo puede enviar de manera segura el inicializador designado a súper en su inicializador.


Cuando crea una subclase, si implementa un inicializador, debe asegurarse de llamar a los inicializadores designados de la superclase, y debe proporcionar al menos un inicializador designado propio, aunque esto puede ser simplemente una anulación de la superclase. .

Como parte de la inicialización de su subclase, debe llamar a uno de los inicializadores designados de la superclase.

La documentación de una clase debe nominar a sus inicializadores designados. Si no, generalmente se supone que el inicializador designado es el inicializador más específico (el que toma la mayor cantidad de argumentos) provisto por la superclase.

Para obtener más información, consulte "El lenguaje de programación Objective-C: Asignación e inicialización de objetos". [Nota: a partir de diciembre de 2013, este contenido ya no parece estar disponible en el centro de documentación de Apple. Lo que era una referencia de lenguaje ha sido reemplazado por más tutoriales orientados a tareas y documentación conceptual.]

En cuanto a sus preguntas específicas:

¿Por qué es esto? Para que la superclase tenga la oportunidad de inicializar su estado. A continuación, puede continuar e inicializar el estado que agrega por encima y más allá de lo que proporciona la superclase.

¿Por qué llamar a la inicial del super desde el initWithFrame de una subclase resulta en un bucle infinito? Porque, para NSView , -init no es el inicializador designado, aunque es el de NSObject . Entonces NSView reemplaza para llamar a su inicializador designado, -initWithFrame: Si ha llamado -init desde su -initWithFrame: , ahora tiene -initWithFrame: llamando -init calling -initWithFrame: calling -init: calling ...

Esto significa…? No, porque esto no es obligatorio. Debe comprender la documentación real, no los rumores.


No sé de dónde lo escuchó, pero AFAIK no es obligatorio. Puede elegir iniciar su subclase con lo que desee, siempre que llame a un método init de la superclase. Cualquier método init funcionará.

Sin embargo, si también tiene la misma función init en su superclase, creo que lo mejor es llamar a esa función y luego agregar su propia personalización. No es obligatorio, es una buena práctica hacerlo, porque esa función de inicio puede proporcionar algunas inicializaciones y configuraciones que puede olvidarse agregar.


desde una perspectiva c ++:

He oído que cuando tienes una subclase, se supone que debes inicializar la superclase con la misma función init desde el init de la subclase. Lo que quiero decir es que el init de la subclase debe llamar a [superinicio] y initWithFrame de la subclase debe llamar a [superinicioWithFrame].

eso no es cierto. es simplemente común. usted es libre de llamar a cualquier inicializador de superclase que esté documentado como un inicializador válido.

puede ayudar a verlo así: observe los iniciadores de la superclase y determine cuáles son compatibles.

  • a veces hay un inicializador designado
  • a veces hay nuevos inicializadores (por ejemplo, uno que puede agregar un argumento a la super-superclase)
  • a veces hay intializadores heredados de la super-superclase

para inicializadores designados: considérelo protegido

para un nuevo inicializador: considéralo protegido

para inicializadores heredados: típicamente se considera privado cuando la superclase declara nuevos inicializadores, de lo contrario, protegido

¿Por qué llamar a la inicial del super desde el initWithFrame de una subclase resulta en un bucle infinito?

tal es el efecto (comportamiento indefinido) de llamar a un intializador al que no debe llamar.

Si esto es necesario, ¿significa esto que no puedo crear una nueva función init dentro de una subclase como initWithPoint y tener esa llamada super init o initWithFrame simplemente porque la superclase no tiene initWithPoint?

esto está bien siempre que llame a través de uno de los inicializadores de superclase admitidos.

Supongo que el corazón de la pregunta aquí es simplemente por qué es incorrecto llamar a una súper clase diferente, algo que me confunde posiblemente debido a mi experiencia en c ++.

objc no admite ocultación / visibilidad para inicializadores. una vez que está en la interfaz de una superclase, está allí (y usted puede tomar malas decisiones cuando el compilador no puede ayudarlo): se espera que determine el gráfico de visibilidad para los inicializadores y escriba su subclase en consecuencia. objc carece de características de lenguaje que está acostumbrado a tener en c ++.