objective-c inheritance casting subclassing

objective c - Cómo lanzar ''Clase A'' a su subclase ''Clase B''-Objective-C



inheritance casting (5)

Estoy usando un marco que define y usa ''ClassA'', una subclase de NSObject. Me gustaría agregar algunas variables y funcionalidad, así que naturalmente creé ''ClassB'', una subclase de ''ClassA''

Ahora mi problema es este. Muchos de los métodos dentro de este marco devuelven instancias de ''ClassA'' que me gustaría convertir a mi subclase.

Por ejemplo toma este método:

- (ClassA *)doSomethingCool:(int)howCool

Ahora en mi código intento esto:

ClassB * objB; objB = (ClassB *)doSomethingCool(10); NSLog(@"objB className = %@", [objB className]);

Esto funciona muy bien. No hay errores de compilación o tiempo de ejecución ni nada. Pero lo que es realmente extraño para mí es la salida:

>> "objB className = ClassA"

El casting obviamente falló. No estoy seguro de lo que sucedió en este momento ... objB se escribe como ''ClassB'', pero className es ''ClassA'' y no responde a ningún método ''ClassB''.

No estoy seguro de cómo es posible ... ¿Alguien sabe qué estoy haciendo mal aquí?

Encontré una publicación similar que es exactamente opuesta a lo que estoy preguntando here


¿Qué sucede cuando llama a uno de sus métodos de subclase en el objeto devuelto?

ClassB * objB; objB = (ClassB *)doSomethingCool(10); [objB subClassMethod];

Obj-C es bastante libre y pierde con los tipos, ni siquiera necesita saber el tipo de antemano, por ejemplo. usted podría cambiar todas sus referencias de ClassB a id. Sé que es más seguro saber que tiene el tipo esperado, pero si su código es correcto, no debería importar.


Casting no convierte de un tipo de objeto a otro. No puede forzar a una biblioteca a cambiar el tipo de objeto y crear otro tipo de objetos a menos que utilice algún patrón de fábrica.


Convertir variables de objeto en Objective-C suele ser un error (hay algunos casos en los que es correcto, pero nunca para este tipo de cosas). Observe que no está lanzando un objeto, está lanzando un puntero a un objeto. Entonces tiene un puntero de tipo ClassB* , pero aún apunta a la misma instancia de ClassA. La cosa apuntada a no ha cambiado en absoluto.

Si realmente desea convertir las instancias de ClassA en ClassB, deberá escribir un método de constructor de ClassB que pueda crear una instancia de ClassB desde un ClassA. Si realmente necesita agregar variables de instancia, esta podría ser su mejor opción.

Sin embargo, como dijo Jason, a menudo es una buena idea probar una categoría primero.


No puedes simplemente lanzar una súper clase a su subclase. En realidad, no implementa ninguna de sus variables / propiedades o métodos agregados. Tan pronto como intente enviar un mensaje con un método que defina en su subclase, obtendrá una excepción de tiempo de ejecución y su aplicación se cerrará. Solo se puede lanzar de forma segura en una dirección: de más específico a más general. Es decir, puede convertir nuestro ClassB en un ClassA de forma segura, utilizando solo los métodos y propiedades de ClassA, pero no al revés.

Piénsalo de esta manera: tienes un Car (la clase padre) y un FourDoorSedan (la subclase). Cada coche tiene un motor y dos puertas. Ahora, digamos que está obteniendo un automóvil de algún lugar, y eso es todo lo que sabe al respecto. Le dices al operador que el auto es un FourDoorSedan, pero en realidad resulta que no lo es. Entonces, cuando el operador hace algo como: openBackPassengerDoor, ¿qué sucede? Solo hay dos puertas !! Es lo mismo aqui.

Si solo desea agregar un poco de funcionalidad a ClassA, consulte las Categorías de Objective-C, probablemente sean lo que usted desea y no será necesario realizar ningún casting. Sin embargo, lea la documentación detenidamente, porque no están exentos de advertencias.


Si solo desea agregar un método a los objetos existentes, la subclase no es la forma correcta. Puede agregar un método a las clases existentes (y sus instancias) usando una función de idioma llamada category .

Ejemplo:

//"ClassA+doSomethingCool.h" @interface ClassA (doSomethingCool) - (ClassA *)doSomethingCool:(int)howCool; @end //"ClassA+doSomethingCool.m" @implementation ClassA (doSomethingCool) - (ClassA *)doSomethingCool:(int)howCool { } @end