Buscar dónde se retiene el object con ARC

Tengo un object que se retiene más de lo necesario (probablemente debido a una propiedad que es strong lugar de weak ). Gran base de código, por lo que es difícil encontrar dónde.

¿Cómo puedo encontrar todas las líneas en las que se retiene este object cuando utilizo ARC?

Si no estuviera usando ARC, supongo que podría simplemente anular retain y verificar desde dónde se llama. ¿Puedo hacer algo similar con ARC?

Para realizar un seguimiento del crecimiento de una aplicación, Heapshot Analysis ha demostrado ser muy eficaz. Captura tanto las filtraciones verdaderas como la acumulación de memory donde las asignaciones no son explicadas por fugas.

Puede ver todos los events de retención / liberación, y su retroceso, utilizando el instrumento Asignaciones. Pulse el pequeño button (i) en el instrumento Asignaciones y active "Grabar counts de reference". Al activar "Solo realizar un seguimiento de las asignaciones activas", se networkinguce la cantidad de datos recostackdos por los instrumentos, haciéndolo más rápido (y las asignaciones no son realmente útiles en este context, pero pueden ser en otras).

Con eso, puede sumergirse en cualquier asignación (haciendo clic en la flecha derecha en el campo de dirección), ver todos los events de retención / liberación y ver exactamente dónde ocurrieron.

introduzca la descripción de la imagen aquí

Me las arreglé para encontrar el retén ofensivo haciendo lo siguiente:

  1. Añada temporalmente -fno-objc-arc a la class de object Banderas del comstackdor para deshabilitar ARC para esa class.
  2. Anule temporalmente la retain (solo llame a super ) y coloque un punto de interrupción en él.
  3. Depura y revisa la stack de llamadas cada vez que se llama.

La semana pasada estaba ayudando a algunos amigos a depurar las fugas en su proyecto ARC. Algunos consejos:

1 / Construir para perfilar y comenzar Instrumentos con detección de fugas. Luego explora los objects actualmente asignados, encuentra el object que deseas (puedes orderarlos por nombre) y mira su historial de retención / liberación. Tenga en count que contar retener no es muy útil con ARC. Debes verificarlo manualmente paso a paso.

Trate de comentar todo el código que podría ser la fuente de la fuga y luego elimine el comentario paso a paso.

2 / Ponga un NSLog en su init y en su dealloc para ver cuándo se crea y destruye el object.

3 / No busque solo las definiciones de properties, observe si los creadores de properties se implementan manualmente. Encontré un problema en el proyecto de mis amigos así:

 @property (weak, nonatomic) id<...> delegate; 
 @interface ... { id<...> _delegate; } @synthesize delegate = _delegate; - (void)setDelegate(id<...>)delegate { _delegate = delegate; //with ARC this retains the object! } 

Esta solución fue de alguna ayuda para mí. Básicamente utiliza el método swizzling para engañar al comstackdor ARC y hacer que piense que no está anulando retener y liberar.

  + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class cls = [self class]; // When swizzling a class method, use the following: // Class class = object_getClass((id)self); SEL originalSelector1 = NSSelectorFromString(@"retain"); SEL swizzledSelector1 = NSSelectorFromString(@"myretain"); SEL originalSelector2 = NSSelectorFromString(@"release"); SEL swizzledSelector2 = NSSelectorFromString(@"myrelease"); Method originalMethod1 = class_getInstanceMethod(cls, originalSelector1); Method swizzledMethod1 = class_getInstanceMethod(cls, swizzledSelector1); Method originalMethod2 = class_getInstanceMethod(cls, originalSelector2); Method swizzledMethod2 = class_getInstanceMethod(cls, swizzledSelector2); BOOL didAddMethod1 = class_addMethod(cls, originalSelector1, method_getImplementation(swizzledMethod1), method_getTypeEncoding(swizzledMethod1)); if (didAddMethod1) { class_replaceMethod(cls, swizzledSelector1, method_getImplementation(originalMethod1), method_getTypeEncoding(originalMethod1)); } else { method_exchangeImplementations(originalMethod1, swizzledMethod1); } BOOL didAddMethod2 = class_addMethod(cls, originalSelector2, method_getImplementation(swizzledMethod2), method_getTypeEncoding(swizzledMethod2)); if (didAddMethod2) { class_replaceMethod(cls, swizzledSelector2, method_getImplementation(originalMethod2), method_getTypeEncoding(originalMethod2)); } else { method_exchangeImplementations(originalMethod2, swizzledMethod2); } }); } -(id)myretain { NSLog(@"tracking retain now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]); SEL selector = NSSelectorFromString(@"myretain"); return [self performSelector:selector withObject:nil]; } -(id)myrelease { NSLog(@"tracking release now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]); SEL selector = NSSelectorFromString(@"myrelease"); return [self performSelector:selector withObject:nil]; 

}

Si está utilizando ARC, nunca obtendrá la opción de agregar retener,

secreenshot1

y si ha convertido el proyecto a ARC utilizando la opción a continuación, se le pedirá un error

captura de pantalla2

Si ha configurado la propiedad como strong , entonces debería asignar el object una vez a través de todo el proyecto, p self.yourobject = [[NSMutableArray alloc]init]; Ej. self.yourobject = [[NSMutableArray alloc]init]; . No hay atajo para esto.