tab bar ios objective-c swift memory-management uiviewcontroller

ios - bar - Deinit no se llama en un UIViewController, pero Dealloc es



uitabbar (2)

No lo he probado todavía, pero encontré this para ti:

Parece que no se llamará a la función a menos que se coloque algún código dentro del deinit (extraño) debe ser parte de la etapa de optimización de swift.

Intente colocar una declaración impresa dentro de su deinit como se sugiere e informe sus hallazgos

Parece que el equivalente Swift de dealloc es deinit . Sin embargo, cuando intenta definir el método en un UIViewController, no se comporta como esperaría ...

Preparar

  1. Cree un nuevo proyecto de Vista única utilizando Xcode 7.0, ya sea en Swift o en Objective-C.
  2. Agregue un botón de "descartar" en el controlador de vista que se creó con el guión gráfico (me referiré a este controlador de vista como VC2; su clase es ViewController).
  3. Agregue un nuevo controlador de vista y configúrelo para que sea el controlador de vista inicial (VC1, la clase es nula).
  4. Agregue un botón "presente" a VC1 con un "Presente Modalmente" segue a VC2.
  5. En el código de VC2, ponga un punto de interrupción en deinit (Swift) o dealloc (Objective-C).
  6. En VC2, haga que la acción del botón "descartar" haga lo siguiente:

    // Swift: presentingViewController?.dismissViewControllerAnimated(true, completion: nil) // Objective-C: [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

  7. Ejecute la aplicación y toque ambos botones para presentar primero VC2 y luego descárguela.

Observe cómo en Objective-C , se dealloc punto de interrupción dealloc .

En Swift , por otro lado, el deinit quiebre deinit nunca se deinit .

¿Por qué nunca se llama deinit ? ¿Es esto un error o por diseño?

Si esto es por diseño, ¿dónde debería colocar el código de limpieza para liberar recursos cuando el controlador de vista ya no será necesario? (No puede estar en viewDidUnload ya que ese método está en desuso. No puede estar en viewDidDisappear porque otra cosa podría tener una referencia a él y, finalmente, volverá a mostrarlo).

Nota: Si intentas definir un método de dealloc en Swift, obtendrás el siguiente error:

El método ''dealloc ()'' con selector de Objective-C ''dealloc'' entra en conflicto con el desinicializador con el mismo selector de Objective-C.

Si tiene el controlador de vista Swift heredado de un controlador de Objective-C, y coloca un punto de interrupción en el método de dealloc de Objective-C, obtendrá el mismo comportamiento de buggy definido anteriormente: no se llamará el dealloc , pero sí el de dealloc . llamado.

Si intenta usar Asignaciones para ver el número de instancias de la clase en la memoria, ambas versiones muestran lo mismo: el # Persistent siempre es 1, y el # Transient aumenta cada vez que muestra el segundo controlador de vista.

Dada la configuración anterior, no debe haber ningún ciclo de referencia fuerte que se mantenga en el controlador de vista.


TLDR:

Los deinit de deinit solo funcionarán en deinit si hay una línea de código ejecutable delante de ellos.

  • Si coloca un punto de interrupción en una línea de código ejecutable, entonces funcionará.
  • La línea de código ejecutable debe pertenecer al método deinit .

Gracias a Adam por indicarme la dirección correcta . No realicé pruebas exhaustivas, pero parece que los puntos de interrupción se comportan de forma diferente en la deinit de deinit que en cualquier otro lugar del código.

Le mostraré varios ejemplos en los que agregué un punto de interrupción en cada número de línea. Aquellos que funcionarán (p. Ej., Pausar la ejecución o realizar su acción, como registrar un mensaje) se indicarán mediante el símbolo ➤.

Normalmente, los puntos de interrupción se alcanzan generosamente, incluso si un método no hace nada:

➤ 1 ➤ 2 func doNothing() { ➤ 3 ➤ 4 } 5

Sin embargo, en un método de deinit en blanco, NO se alcanzarán puntos de interrupción:

1 2 deinit { 3 4 } 5

Al agregar más líneas de código, podemos ver que depende de si hay una línea de código ejecutable después del punto de interrupción:

➤ 1 ➤ 2 deinit { ➤ 3 // ➤ 4 doNothing() ➤ 5 // ➤ 6 foo = "abc" 7 // 8 } 9

En particular, preste mucha atención a las líneas 7 y 8, ya que esto difiere significativamente de cómo se doNothing() .

Si se acostumbró a este comportamiento de cómo funcionaba el punto de interrupción en la línea 4 en doNothing() , puede deducir incorrectamente que su código no se está ejecutando si solo tenía un punto de interrupción en la línea 5 (o incluso 4) en este ejemplo:

➤ 1 ➤ 2 deinit { ➤ 3 number++ 4 // incrementNumber() 5 } 6

Nota: para los puntos de interrupción que pausan la ejecución en la misma línea, se golpean en el orden en que se crearon. Para probar su orden, establezco un punto de interrupción en el mensaje de registro y continúo automáticamente después de evaluar las acciones .

Nota: En mi prueba también hubo otro error potencial que podría encontrarlo: si usa print("test") , aparecerá el área de depuración para mostrarle el mensaje (el mensaje aparece en negrita). Sin embargo, si agrega un punto de interrupción y le dice que registre un mensaje , lo registrará en texto regular y no abrirá el área de depuración. Tienes que abrir manualmente el área de depuración para ver el resultado.

Nota: todo esto fue probado en Xcode 7.1.1