Cómo liberar un componente en Android / iOS
Creo dinámicamente un TEdit
en un formulario de Android:
edit := TEdit.Create(Self);
Quiero liberarla usando edit.Free
, pero todavía apenas en forma.
- Determinación de la posición relativa de 2 dispositivos móviles mediante ultrasonidos
- Encriptación AES en iOS y Android, y descifrado en C # .NET
- Escucha tocar y arrastrar el valor y la función en consecuencia
- Ver / Lib de WMS para Android / iOS
- NoSQL incorporado sin servidor para Android e iOS
Este código funciona bien en win32, pero no en Android.
Lo mismo parece suceder no sólo para TEdit, sino para cualquier componente que utilice Android o iOS.
- Es su cualquier reglas para configurar el tamaño de los iconos / fuentes / etc .. de acuerdo con el tamaño de la pantalla
- Integración de Facebook para aplicaciones móviles con una API REST de servidor
- Intel TBB para Android e iOS
- ¿Cómo puedo obtener el estado del timbre / estado de silencio de un dispositivo usando Cordova?
- Formato de archivo qcar-resource.dat del SDK de QCAR (Vuforia)
- Push notificaciones en las 3 plataformas (android, ios, windows phone)
- Acelerar la búsqueda de video HTML5?
- PlayN - Teclado virtual en iOS y Android
Respuesta corta
Hay dos reglas que deben seguirse al liberar cualquier objeto descendente de TComponent
en los compiladores de Delphi ARC (actualmente Android e iOS):
- El uso de
DisposeOf
es obligatorio independientemente del objeto que tenga el propietario o no - En los destructores o en los casos en que la referencia no va a salir del ámbito de aplicación poco después de que
DisposeOf
se llame, la referencia de objeto también debe establecerse anil
(explicación detallada en Pitfalls)
Puede resultar atractivo tener el método DisposeOfAndNil
, pero ARC lo hace mucho más complicado de lo que era el caso con el antiguo método FreeAndNil
y sugeriría usar la secuencia DisposeOf - nil
para evitar problemas adicionales:
Component.DisposeOf; Component := nil;
Mientras que en muchos casos el código funcionará correctamente incluso si las reglas anteriores no se siguen, tal código sería bastante frágil y podría romperse fácilmente por otro código introducido en lugares aparentemente no relacionados.
DisposeOf en el contexto de la gestión de memoria ARC
DisposeOf
rompe ARC. Esto viola la regla de oro de ARC Cualquier referencia de objeto puede ser una referencia de objeto válida o nula e introduce una tercera referencia de objeto "zombie" con disposición estatal.
Cualquier persona que intenta entender la gestión de memoria ARC debe mirar a DisposeOf
como la adición que sólo resuelve Delphi problemas de marco específico y no concepto que realmente pertenece a ARC en sí.
¿Por qué existe DisposeOf en los compiladores de Delphi ARC?
TComponent
clase TComponent
(y todos sus descendientes) fue diseñada teniendo en cuenta la gestión manual de la memoria. Utiliza un mecanismo de notificación que no es compatible con la administración de memoria ARC porque se basa en romper ciclos de referencia fuertes en destructor. Dado que TComponent
es una de las clases base en las que se basan los frameworks de Delphi, debe ser capaz de funcionar correctamente bajo la administración de memoria ARC.
Además Free Notification
mecanismo de Free Notification
hay otros diseños similares en marcos de Delphi adecuados para la gestión de memoria manual porque se basan en romper ciclos de referencia fuertes en destructor, pero esos diseños no son adecuados para ARC.
DisposeOf
método DisposeOf
permite la llamada directa del destructor de objetos y permite que dicho código heredado se reproduzca junto con ARC.
Una cosa hay que señalar aquí. Cualquier código que utiliza o hereda de TComponent
automáticamente se convierte en código heredado en el contexto de la administración ARC adecuada, incluso si la escribe hoy.
Cita del blog de Allen Bauer Entregue al lado de ARC
Entonces, ¿qué otra cosa DisoseOf resolver? Es muy común entre varios marcos de Delphi (VCL y FireMonkey incluidos), colocar el código activo de notificación o de gestión de listas dentro del constructor y destructor de una clase. El modelo propietario / propietario de TComponent es un ejemplo clave de tal diseño. En este caso, el diseño del marco de componentes existente se basa en muchas actividades distintas de la simple "gestión de recursos" que se producirán en el destructor.
TComponent.Notification () es un ejemplo clave de tal cosa. En este caso, la forma correcta de "desechar" un componente, es usar DisposeOf. Un derivado TComponent no suele ser una instancia transitoria, sino que es un objeto de vida más larga que también está rodeado por un sistema completo de otras instancias componentes que componen cosas como formas, marcos y datamodules. En este caso, el uso de DisposeOf es apropiado.
Cómo funciona DisposeOf
Para tener una mejor comprensión de lo que sucede exactamente cuando se llama a DisposeOf
, es necesario saber cómo funciona el proceso de destrucción de objetos de Delphi.
Hay tres fases distintas involucradas en la liberación de objetos tanto en ARC como en compiladores Delphi no ARC
- Destructor
destructor Destroy
cadena de métodos - Limpieza de campos administrados por objetos: cadenas, interfaces, matrices dinámicas (en el compilador ARC que incluye referencias de objetos simples, también)
- Liberar memoria de objetos del montón
Liberación de objetos con compiladores que no son ARC
Component.Free
-> ejecución inmediata de las etapas 1 -> 2 -> 3
Liberación de objetos con compiladores ARC
-
Component.Free
oComponent := nil
-> disminuye el recuento de referencia del objeto seguido de a) o b)- A) si el recuento de referencia del objeto es 0 -> ejecución inmediata de las etapas
1 -> 2 -> 3
- B) si el recuento de referencia de objeto es mayor que 0, nada más sucede
- A) si el recuento de referencia del objeto es 0 -> ejecución inmediata de las etapas
-
Component.DisposeOf
-> ejecución inmediata de la etapa1
, las etapas2
y3
se ejecutarán más tarde cuando el recuento de referencia de objetos llega a 0.DisposeOf
no disminuye el recuento de referencia de la referencia de llamada.
Sistema de notificación TComponent
Free Notification
mecanismo de notificación Free Notification
TComponent
Free Notification
a los componentes registrados que se está liberando la instancia de componente particular. Los componentes notificados pueden manejar esa notificación dentro del método de Notification
virtual y asegurarse de que eliminan todas las referencias que pueden tener sobre el componente que se está destruyendo.
Bajo compiladores que no son ARC, este mecanismo garantiza que no terminen con punteros que apuntan a objetos no válidos y bajo compiladores ARC, borrar las referencias al componente de destrucción disminuirá su recuento de referencia y romperá ciclos de referencia fuertes.
Free Notification
mecanismo de Free Notification
está siendo activado en el destructor TComponent
y sin DisposeOf
y la ejecución directa del destructor, dos componentes podrían mantener referencias fuertes entre sí manteniéndose activos durante toda la vida útil de la aplicación.
FFreeNotifies
lista FFreeNotifies
que contiene la lista de componentes interesados en la notificación se declara como FFreeNotifies: TList<TComponent>
y almacenará una referencia fuerte a cualquier componente registrado.
Por ejemplo, si tienes TEdit
y TPopupMenu
en tu formulario y asignas ese menú emergente para editar la propiedad PopupMenu
, editará una fuerte referencia al menú emergente en su campo FEditPopupMenu
y el menú emergente contendrá una fuerte referencia para editar en su lista FFreeNotifies
. Si desea liberar cualquiera de estos dos componentes tiene que llamar a DisposeOf
o simplemente continuará existiendo.
Si bien puede intentar rastrear esas conexiones manualmente y romper ciclos de referencia fuertes antes de liberar cualquiera de los objetos que pueden no ser tan fáciles de hacer en la práctica.
El siguiente código básicamente fuga ambos componentes bajo ARC porque mantendrán una referencia fuerte el uno al otro y, una vez finalizado el procedimiento, ya no tendrá referencias externas que apunten a ninguno de esos componentes. Sin embargo, si reemplaza Menu.Free
con Menu.DisposeOf
activará el mecanismo de Free Notification
y romperá el ciclo de referencia fuerte.
procedure ComponentLeak; var Edit: TEdit; Menu: TPopupMenu; begin Edit := TEdit.Create(nil); Menu := TPopupMenu.Create(nil); Edit.PopupMenu := Menu; // creating strong reference cycle Menu.Free; // Menu will not be released because Edit holds strong reference to it Edit.Free; // Edit will not be released because Menu holds strong reference to it end;
Trampas de DisposeOf
Además de romper ARC, eso es malo por sí solo, porque cuando lo rompes no tienes mucho uso de él, también hay dos problemas importantes con cómo DisposeOf
se implementa que los desarrolladores deben ser conscientes.
1. DisposeOf
no disminuye el recuento de referencia en la referencia de llamada Informe QP RSP-14681
type TFoo = class(TObject) public a: TObject; end; var foo: TFoo; b: TObject; procedure DoDispose; var n: integer; begin b := TObject.Create; foo := TFoo.Create; foo.a := b; foo.DisposeOf; n := b.RefCount; // foo is still alive at this point, also keeping b.RefCount at 2 instead of 1 end; procedure DoFree; var n: integer; begin b := TObject.Create; foo := TFoo.Create; foo.a := b; foo.Free; n := b.RefCount; // b.RefCount is 1 here, as expected end;
2. DisposeOf
no limpia las referencias de tipos administrados internos de la instancia Referencia QP RSP-14682
type TFoo = class(TObject) public s: string; d: array of byte; o: TObject; end; var foo1, foo2: TFoo; procedure DoSomething; var s: string; begin foo1 := TFoo.Create; foo1.s := 'test'; SetLength(foo1.d, 1); foo1.d[0] := 100; foo1.o := TObject.Create; foo2 := foo1; foo1.DisposeOf; foo1 := nil; s := IntToStr(foo2.o.RefCount) + ' ' + foo2.s + ' ' + IntToStr(foo2.d[0]); // output: 1 test 100 - all inner managed references are still alive here, // and will live until foo2 goes out of scope end;
Solución alternativa
destructor TFoo.Destroy; begin s := ''; d := nil; o := nil; inherited; end;
El efecto combinado de las cuestiones anteriores puede manifestarse de diferentes maneras. De mantener más memoria asignada de lo necesario a difícil de atrapar bugs que son causados por el conteo de referencia incorrecto, inesperado de objetos no pertenecientes contenidos y referencias de interfaz.
Dado que DisposeOf
no disminuye el recuento de referencia de referencia de llamada, es importante nil
dicha referencia en destructores, de lo contrario las jerarquías de objetos enteros pueden permanecer vivas mucho más tiempo de lo necesario y en algunos casos incluso durante toda la vida útil de la aplicación.
3. DisposeOf
no se puede utilizar para resolver todas las referencias circulares
El último, pero no menos importante, con DisposeOf
es que romperá las referencias circulares sólo si hay código en el destructor que las resuelve, como lo TComponent
sistema de notificación TComponent
.
Estos ciclos que no son manejados por el destructor deben ser rotos utilizando atributos [weak]
y / o [unsafe]
en una de las referencias. Esa también es la práctica ARC preferida.
DisposeOf
no debe utilizarse como solución rápida para romper todos los ciclos de referencia (los que nunca fue diseñado para), ya que no funcionará y abusar de ella puede dar lugar a difíciles de detectar pérdidas de memoria.
Ejemplo simple de ciclo que no será roto por DisposeOf
es:
type TChild = class; TParent = class(TObject) public var Child: TChild; end; TChild = class(TObject) public var Parent: TParent; constructor Create(AParent: TParent); end; constructor TChild.Create(AParent: TParent); begin inherited Create; Parent := AParent; end; var p: TParent; begin p := TParent.Create; p.Child := TChild.Create(p); p.DisposeOf; p := nil; end;
Por encima del código se verán tanto las instancias de objeto primario como secundario. Combinado con el hecho de que DisposeOf
no borra los tipos administrados internos (incluidas las cadenas), esas filtraciones pueden ser enormes dependiendo del tipo de datos que se estén almacenando en el interior. La única manera (correcta) de romper ese ciclo es cambiando la declaración de clase TChild
:
TChild = class(TObject) public [weak] var Parent: TParent; constructor Create(AParent: TParent); end;
En las plataformas móviles la vida útil se gestiona mediante ARC. Los objetos sólo se destruyen cuando no hay referencias al objeto que queda. Su objeto tiene referencias a él, específicamente de su padre.
Ahora puede usar DisposeOf
para forzar el objeto a ser destruido. Más detalles aquí: http://blogs.embarcadero.com/abauer/2013/06/14/38948
Sin embargo, sospecho que una mejor solución sería eliminar las referencias al objeto. Quitarlo de su recipiente. Por ejemplo, estableciendo su padre a ser cero.
- Java – Comparación de clases?
- Objetos personalizados en la lista AlertDialog; Cómo obtener una cadena de pantalla y luego el valor real?