thread exc_bad_access exc code bad address 0x0 iphone objective-c memory-management exc-bad-access

iphone - thread 1 exc_bad_access code 1 address 0x0



Evitar EXC_BAD_ACCESS cuando se usa el patrĂ³n delegado (5)

A tiene un controlador de vista, y crea un objeto "descargador", que tiene una referencia al controlador de vista (como delegado). El descargador vuelve a llamar al controlador de vista si descarga correctamente el elemento. Esto funciona bien mientras permanezca en la vista, pero si se aleja antes de que se complete la descarga, obtengo EXC_BAD_ACCESS . Entiendo por qué sucede esto, pero ¿hay alguna manera de verificar si un objeto todavía está asignado? Intenté probar utilizando delegate != nil , y [delegate respondsToSelector:] , pero se ahoga.

if (!self.delegate || ![self.delegate respondsToSelector:@selector(downloadComplete:)]) { // delegate is gone, go away quietly [self autorelease]; return; } else { // delegate is still around [self.delegate downloadComplete:result]; }

Sé que podría

a) hacer que los objetos descargados retengan el controlador de vista

b) mantener una serie de descargadores en el controlador de vista y establecer sus valores de delegado en cero cuando desasigno el controlador de vista.

Pero me pregunto si hay una manera más fácil, ¿en donde acabo de probar si la dirección del delegado contiene un objeto válido?


Acabo de encontrarme con este problema y lo resolví. Para ARC, la solución es usar el atributo weak lugar de assign .

El choque viene porque el delegado

  1. Tiene un atributo de assign , AND
  2. Ha sido desasignado

La solución es usar el atributo weak , porque cuando el objeto se desasigna, el puntero se establecerá en nil . Entonces, cuando su código llame a respondsToSelector en un nil , Objective C ignorará la llamada y no se bloqueará.

En su código, cuando intenta llamar al método respondsToSelector en el delegate , obtiene un EXC_BAD_ACCESS. Esto se debe a que los objetos que utilizan la propiedad de assign no se establecerán en nil cuando se desasignen. (Por lo tanto, ¿por qué hacer un !self.delegate antes de respondsToSelector no evita que se llame a responseToSelector en un objeto desasignado, y sigue bloqueando su código)

Como ya se mencionó, el uso de un atributo strong o de assign en un delegado (como muchos lo han mencionado) en ARC resultará en un ciclo de retención. Así que no lo hagas, no necesitas hacerlo.


Me encontré con esta pregunta porque mi objeto "descargador" me estaba dando EXC_BAD_ACCESS. Mi solución fue cancelar el objeto descargador justo antes de que lo lanzara. Suponiendo que esté utilizando NSURLConnection en su objeto de descarga, llame al método de cancelación.

Es importante tener en cuenta que si NSURLConnection no está descargando nada, la cancelación de llamadas provocará un bloqueo. Necesitará algo de lógica para verificar si hay una descarga en curso.


No, no puede (útilmente) "probar si una dirección contiene un objeto válido". Incluso si pudieras buscar dentro de las partes internas del sistema de asignación de memoria y determinar que tu dirección apunta a un objeto válido, eso no necesariamente significaría que era el mismo objeto al que te referías anteriormente: el objeto podría haber sido desasignado y otro objeto creado en la misma dirección de memoria.

Retener al delegado es la forma habitual de resolver esto. Su opción (b) rompe la encapsulación de objetos y puede tener problemas de seguridad de subprocesos.


También tengo problemas con la referencia débil del delegado, y actualmente solo tengo una solución para este problema: usar la referencia fuerte para el delegado, y configurar manualmente self.delegate = nil; después de que mi código esté completo Esta solución funciona para mí en la carga asíncrona de imágenes, donde tiene un ciclo de vida con final visible.


Yo solo escribiría

SEL slc = @selector(theSlc); if ([delegate respondsToSelector:slc]) { [delegate performSelector:slc]; }

Si el objeto es válido, se llamará al método, de lo contrario no. Usted no tiene que verificar

self.delegate != nil