Llamar a super en la implementación de un bloque Objective-C

Está llamando a un método en súper apoyado en la implementación de un bloque Objective-C?

Cuando estaba llamando a un método súper an EXC_BAD_ACCESO se lanzaría un error, pero tan pronto como cambie esas llamadas de [super methodToCall] a [self methodToCall] y dejar que el mensaje suba por la cadena de respuesta, funcionó bien.

No hay implementación de -methodToCall en la instancia de la clase en la que existe el bloque, pero hay una en la superclase (es decir, la clase de la que uno mismo hereda).

Solo tengo curiosidad por conocer los detalles de por qué llamar a un método en super dentro de la implementación de un bloque fue un problema en primer lugar (técnicamente) para poder evitarlo en el futuro. Tengo la sospecha de que está relacionado con cómo se capturan las variables en el bloque y algo sobre la pila y el montón, pero realmente no tengo una idea concreta.

Nota: el código de implementación del bloque se llama hasta unos segundos después de que el bloque se almacena en una propiedad, la propiedad utiliza copia así que no creo que sea un problema con el ciclo de vida del bloque, todo parece estar bien. Además, esto solo fallaba en el dispositivo iPhone (3G) pero funcionaba sin fallar en el simulador de iPhone.

Resultados en EXC_BAD_ACCESS:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

Funciona perfecto, implementaciones de -didRetrieveItems y -errorRetrievingItems están en la superclase.

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

preguntado el 12 de diciembre de 10 a las 00:12

2 Respuestas

Técnicamente, este es un problema con el tiempo de ejecución de Objective-C y la mecánica subyacente de cómo las llamadas a super realmente funciona. Básicamente, capturan tanto el objeto que es el destinatario del mensaje (self en todos los casos) y la clase que implementa la versión específica del método (la superclase de la clase en la que ocurre la implementación del método). Debido a que gran parte de la preparación para el envío de un mensaje de este tipo ocurre en tiempo de compilación, no en tiempo de ejecución, no me sorprendería que interactuara mal con los bloques.

Lo comprobaría para ver si self sigue siendo válido cuando el mensaje está a punto de enviarse. Normalmente, cualquier objeto referenciado en un bloque se retiene automáticamente. Desde super funciona de forma un poco diferente, podría significar que self no se retiene como cabría esperar. Una forma sencilla de comprobarlo sería utilizar las llamadas para super como se escribió originalmente, y simplemente filtrar el objeto al que se hace referencia como selfy ver si funciona. Si este resulta ser el problema, es posible que deba insertar una referencia ficticia a self dentro del bloque para obtener esa gestión automática de la memoria.

Sin embargo, en el sentido más estricto, no estoy seguro de que pueda depender de que esto funcione para siempre. Aunque los bloques pueden capturar el estado de tiempo de ejecución actual, realmente no tiene sentido (desde una perspectiva de programación orientada a objetos) que rompan la encapsulación e invoquen implementaciones de superclase, ya que la jerarquía nivel en el que se implementan los métodos debe ser opaco a cualquier código de llamada externo. Intentaría encontrar otra solución que no dependa de la jerarquía de herencia.

Respondido el 12 de diciembre de 10 a las 03:12

Gracias por tu explicación detallada, ¡te lo agradezco! - Andrés

No es un problema. Ciertamente es un tema interesante que no se me había ocurrido antes. - Justin Spahr-Summers

Resultados en EXC_BAD_ACCESS:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

Probablemente debido a un error en el compilador; intenta agregar [self class]; o cualquier otro método llamado a self en ese bloque y probablemente funcionará.

Funciona perfectamente, las implementaciones de -didRetrieveItems y -errorRetrievingItems están en la superclase.

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

Creo que puede estar confundido acerca de uno de los aspectos fundamentales de la programación orientada a objetos. Dices que no hay implementaciones de esos métodos en tu clase, solo existen en la superclase.

Debido a la herencia, su clase también responde eficazmente a dichas llamadas de método. Solo llámalos como lo haces arriba usando self. ¡Funcionará, encuentre y es exactamente como debería hacerlo!

Respondido el 12 de diciembre de 10 a las 03:12

¡Doh, a veces simplemente escribo sin pensar realmente en lo que estoy haciendo! Por alguna razón, estaba pensando que se estaba moviendo hacia arriba en la cadena de respuesta, no pensé lo suficiente como para darme cuenta de que simplemente estaba heredando los métodos de las superclases. Un principio tan básico para pasar por alto, ¡estás en el clavo! Gracias por avisarme de eso. - Andrés

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.