2010-09-10 18 views
36

Tengo una aplicación SDK de iPhone que tiene varias vistas que aparecen y desaparecen a medida que el usuario crea contenido. Después de usar la aplicación en un dispositivo por un tiempo, me sale el siguiente choque:Despliegue de UIScrollView EXC_BAD_ACCESS en iOS SDK

Program received signal: “EXC_BAD_ACCESS”. 
(gdb) backtrace 
#0 0x33369ebc in objc_msgSend() 
#1 0x320e5248 in -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded]() 
#2 0x338b4a14 in -[NSObject performSelector:withObject:]() 
#3 0x320e5098 in -[UIAnimator stopAnimation:]() 
#4 0x320e4b7c in -[UIAnimator(Static) _advance:]() 
#5 0x320e4a34 in LCDHeartbeatCallback() 
#6 0x34350e60 in HeartbeatVBLCallback() 
#7 0x332e91c0 in IOMobileFramebufferNotifyFunc() 
#8 0x316532f8 in ??() 
#9 0x33866b50 in __CFMachPortPerform() 
#10 0x338ae52a in CFRunLoopRunSpecific() 
#11 0x338adc1e in CFRunLoopRunInMode() 
#12 0x3434e1c8 in GSEventRunModal() 
#13 0x32002c30 in -[UIApplication _run]() 
#14 0x320in UIApplicationMain() 
#15 0x00002ff8 in main (argc=1, argv=0x2ffff550) at /Developer/svn/MyCompany/iPhone/MyApplication/Other Sources/main.m:14 

Como se puede ver en la traza, la única mención de mi código de allí es la llamada a la principal.

He ejecutado Build and Analyze de Xcode, y también lo configuré para ejecutar el analizador de clang en mi proyecto desde la Terminal, y ninguno de los dos puede encontrar ningún problema en el código. Estoy usando una versión de lanzamiento muy reciente del iOS SDK (todavía no descargué el 4.1, pero el que estoy usando es el que estaba en lanzamiento justo antes de 4.1).

Además, he ejecutado la aplicación en Instruments with the Simulator, y la aplicación no tiene pérdidas de memoria.

que voy a tratar de utilizar la variable NSZombieEnabled y ver si se encuentra cualquier cosa, pero el problema es que necesito para usar la aplicación durante 30 a 40 minutos más o menos antes de que se estrelle, y sospecho que NSZombieEnabled no puede incluso ayúdame a encontrar el problema.

Parece que los bloqueos que he visto es cuando una vista modal llama a un delegado en el controlador de vista principal. El controlador de vista principal luego procesa algo antes de descartar el controlador de vista modal. Hay algunas referencias en el choque a la animación y las vistas de desplazamiento, pero no estoy seguro de qué podría estar haciendo para causar problemas. ¿Alguien tiene alguna sugerencia de cosas que buscar?

EDIT: He puesto la bandera NSZombieEnabled en la aplicación, y en el dispositivo, que viene con este mensaje en la consola:

2010-09-11 17:10:33.970 MyApplication[9321:207] *** 
-[MyViewController respondsToSelector:]: message 
sent to deallocated instance 0x7489480 

Por lo que yo puedo decir, me he fijado Los delegados usaron en la aplicación nil en los desgloses de todas mis clases, así que estoy atascado en cuanto a dónde mirar a continuación.

He intentado utilizar el comando dirección malloc_history pid en esto, pero dijo que no podía encontrar el proceso, he intentado 9321, 9321: 207 y 207. Además, si intenta utilizar la variable MallocStackLogging, la programa no se ejecutará en el dispositivo, obtengo un grupo de malloc: incapaz de crear mensajes de directorio de registro de pila en la consola y un bloqueo del programa.

Ah, y dicho sea de paso, no puedo usar los zombies que comprueban los instrumentos, ya que no parece funcionar con un dispositivo, y no puedo obtener el mismo bloqueo en el simulador.

Respuesta

42

El UIScrollView en el marco de la pila # 1 probablemente quiere informar a su delegado sobre la finalización de la animación, pero el delegado se ha ido en ese momento. El ajuste NSZombieEnabled probablemente confirme esto.

Los delegados no se conservan, por lo que este es un error común en Cocoa y Cocoa Touch. Busque a los delegados en UIScrollView o UITableView en su código y trate de averiguar cuál podría ser lanzado antes de tiempo.

+0

1 no existente. Para ser explícito, las propiedades de delegado siempre deben establecerse en 'assign' y no' retain' –

+0

. Siempre hay una excepción a la regla. Ver 'NSURLConnection' por una razón válida para retener un delegado. –

+0

Tengo un UITableView que reside en un UIViewController, y cuando la aplicación falla, creo que se está preparando para volver a este controlador de vista. Sin embargo, el delegado para este UITableView está configurado en Interface Builder, y no se cambia en ninguna parte del código. –

3

Supongo que el delegado de scrollview está configurado para un objeto que ha sido desasignado. Intente configurar todos los delegados de los objetos secundarios a cero en sus métodos dealloc.

61

Acabo de solucionar este problema yo mismo.

tuve un problema donde:

  • Un delegado ScrollView estaba conectado a un UIViewController
  • El ScrollView comenzó animando
  • El delegado fue y dealloc fue llamado.

El problema fue la ScrollView mensajes delegados estaban disparando en un objeto de nueva desasignado, y los registros de errores eran un poco confuso, ya que apuntaban a referencias a objetos sin sentido.

La solución consistía en establecer el delegado scrollview en nil como la primera línea de mi método dealloc de controlador de vista.

Espero que esto ayude a alguien más!

+5

Probablemente no tengas idea de la cantidad de problemas que acabas de salvarme con esta respuesta, gracias: D – rastating

+0

¡Gracias por esta respuesta! Me ahorró mucho tiempo – derpoliuk

+0

Seguí la respuesta de las fichas antes, pero esto tiene más sentido para mí y me ayuda a mantener mi código limpio. Gracias. +1 – Avi

16

Para mayor información, agrego este seguimiento de pila (iOS 6) para aquellos que pueden encontrar el mismo problema pero con una implementación un poco diferente y los pasos exactos para reproducir el problema.

Exception Type: EXC_BAD_ACCESS (SIGSEGV) 
Exception Codes: KERN_INVALID_ADDRESS at 0x71f05631 
Crashed Thread: 0 

Thread 0 name: Dispatch queue: com.apple.main-thread 
Thread 0 Crashed: 
0 libobjc.A.dylib     0x3919b5d0 objc_msgSend + 1 
1 UIKit       0x33421830 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 48 
2 UIKit       0x334217ba -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 130 
3 UIKit       0x334216a4 -[UIAnimator stopAnimation:] + 460 

esto está sucediendo en iOS 6 y comenzó a ocurrir cuando he implementado el método UIScrollViewDelegate:

" -(void)scrollViewDidEndDecelerating:(UITableView *)tableView" 
and made a call to: 
"[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];". 

ha producido el problema cuando la animación comenzó y presioné el botón "Atrás" y mi punto de vista el controlador se desconectó antes de completar la animación.

Al reproducir, debe asegurarse de presionar el botón "Atrás" después de que comience la animación, pero antes de que se complete. Me tomó algunos intentos. Intenté recrear el problema apagando programáticamente el controlador de vista, pero no pude reproducirlo. Tuve que usar el botón "Atrás". Simplemente había estado llamando a [myTableView release] en el trato. La solución fue como se describe aquí para configurar ambas de estas propiedades a cero:

self.myTableView.delegate = nil; 
self.myTableView = nil; 
+0

gracias amigo. me estaba volviendo loco ... –

+0

Gracias, no pude resolver este accidente durante todo el día ... – Nikita

2

Esto puede suceder si ha insertado un controlador de actualización en una vista de tabla como una subvista (mi sugerencia, nunca haría eso) ...

+0

¿Tiene alguna prueba? Hizo el cambio, pero no estoy seguro de si solucionará el bloqueo. – mOp

+0

según mi propia experiencia (y exactamente el mismo problema), ya que algunas partes de la API anterior asignan (en lugar de la nueva debilidad y, por lo tanto, cuelgan con punteros muertos): este es el caso si insertas UIRefreshController como Subvista (¡NUNCA HAGA ESTO! UIRefreshController no debe insertarse como subvista) –

+0

Encontré el mismo error y sospeché que el problema era insertar un UIRefreshController como una subvista de un objeto UITableView. Según la documentación de Apple, UIRefreshControl solo debe usarse con un UITableViewController, pero yo estaba tratando con un UIViewController heredado. Después de una nueva depuración, descubrí que el problema era que la aplicación estaba perdiendo una referencia de un objeto creado en uno de mis métodos UITableViewDelegate en el UIViewController. Todo lo que tenía que hacer era crear una propiedad en UIViewController y configurarla para ese objeto. – Vee

7

Al principio, delegados debe ser de débil/asignar tipo. Pero evento en este caso hay un obstáculo sutil muy común impulsado por animaciones de desplazamiento. Si utiliza contenidos animados para compensar los cambios sus ScrollViews necesita que configure su delegado a nula en dealloc método.

De lo contrario obtendrá la siguiente

[YourViewController respondsToSelector:]: message sent to deallocated instance 

El ejemplo muy común:

1. _tableView is ivar of YourViewController 
2. _tableView.delegate = self; 
3. - (void)scrollViewDidScroll:(UIScrollView *)scrollView is implemented at YourViewController 
4. at some point you call [_tableView scrollToRowAtIndexPath:indexPath 
    atScrollPosition:UITableViewScrollPositionBottom animated:YES]; 
    or [_tableView setContentOffset:CGPoint animated:YES] 
    and try to close YourViewController 

El _tableView es retenido por CoreAnimation, pero YourViewController se desasigna!

+1

Tengo un problema similar, creo que ... está en el método delegado scrollView didScroll. Pero ahora es un proyecto de ARC, ¿cómo podría suceder eso? – logixologist

+3

+1 para '_tableView' es retenido por CoreAnimation – fatuhoku

2

Todo lo anterior no solucionó mi problema, así que volví a cavar mi código. Reconocí que el bloqueo aparece cuando realizo el teclado y la animación UICollectionView (sí, es un chat) y descarto el controlador actual.

aplicación se bloquea porque trato de hacer el desplazamiento en el bloque finalización de animación :)

Acaba de cortar y todo funciona bien ahora!

codificación y depuración feliz :)

1

Después de enfrentar el mismo problema me puse:

self.collectionView.delegate = nil; 

en - (void)viewDidLoad (antes de realmente establecer ViewController como CollectionView delegado) y -(void)viewWillDisappear:(BOOL)animated

Todo funciona bien ahora.

Gracias por la ayuda.

0

que he visto este tipo de comportamiento, cuando scrollToRowAtIndexPath llamada con indexPath

Cuestiones relacionadas