WeakRef y la gestión de memoria

La programación orientada a objetos con Xojo, y en este caso también a Eventos, es simplemente maravillosa. Básicamente, creas los objetos a partir de las clases definidas y los hechas a rodar. A partir de ahí, las interacciones realizadas por el usuario son las que determinan como interactúan los objetos entre sí con el envío de mensajes de unos a otros (llamadas a métodos), accesos a propiedades y ejecución de eventos. Sin embargo, a veces, la combinación simplemente puede llegar a situaciones inestables por la propia naturaleza de nuestras aplicaciones, y se producen fallos en la gestión de memoria que podemos mantener bajo control con la clase WeakRef.

 

Descarga el código fuente correspondiente a la aplicación de ejemplo desde aquí.

 

Esto es lo que me ha pasado sin ir más lejos recientemente en la implementación de una nueva característica de mi aplicación de productividad Snippery, donde en uno de esos casos poco probables pero posibles uno de los objetos quedaba en un estado inestable. ¿Qué significa esto? Pues que la referencia del objeto (almacenada por una propiedad) no quedaba marcado como nil al no realizarse una correcta liberación de la memoria, de modo que no se podía comprobar el acceso previo a sus propiedades y métodos mediante una simple comprobación del tipo:

if miPropiedad = nil then …

De hecho, la propiedad mantenía la referencia al objeto original; pero lo cierto es que si se inspeccionaba dicho objeto en tiempo de ejecución mediante el depurador de Xojo, su estructura interna simplemente había desaparecido y, por tanto, eso explicaba el error de obtenido durante la ejecución de la aplicación y uno de los mensajes de error más significativos del Sistema:

EXC_BAD_ACCESS (SIGSEGV)

La clase WeakRef procura una referencia débil al objeto referenciado.
Salida inesperada de la aplicación por uso de un vector de memoria inválido.

Es decir, intento de acceso a un vector de memoria en el que esperábamos encontrar una estructura de datos y que ha dejado de ser así (las clases y, por tanto los objetos son estructuras).

He de decir que en posteriores investigaciones sobre el tema he comprobado que dicho error no siempre se produce, y que puede depender del tipo de objeto del que mantengamos la referencia o incluso la propiedad a la que intentemos acceder o el método que intentemos llamar cuando dicho objeto se encuentra en este estado “inestable”. En el mejor de los casos, simplemente no pasa nada. En el peor de los casos (el más probable)… tu aplicación sufrirá una salida inesperada de las que no puedes gestionar mediante el bloque Try… Catch o con la Gestión de Excepciones en tiempo de ejecución (los intentos de acceso a vectores de memoria corrompidos escapan a la gestión que pueda realizar el framework de Xojo).

Si quieres ver por ti mismo de lo que estoy hablando, puedes decargar la aplicación de ejemploque he preparado para que se produzca un error como el descrito.

WeakRef al rescate

¿Cómo podemos resolver este tipo de situaciones? Fácil. Xojo pone a nuestra disposición la clase WeakRef que nos permite mantener referencias débiles sobre los objetos. Cuando envolvemos una instancia de objeto en la que estamos interesados dentro de una instancia de la clase WeakRef, nos aseguraremos de que dicha referencia quede liberada (y por tanto pase a ser nil) mediante una correcta gestión de la memoria. Así, problema resuelto; dado que ya podemos realizar una comprobación condicional contra nil antes de intentar acceder a cualquiera de las propiedades del objeto propiamente dicho.

Es decir, en el caso de nuestra aplicación de ejemplo, resolveremos el problema con los siguientes cambios:

1. Definimos la propiedad sourceControl de la clase Worker para que sea del Tipo de Dato WeakRef
2. En el constructor de la clase Worker el código pasa a ser el siguiente:

sourceControl = new weakref( c )

3. En el método Work de la clase Worker modificaremos el bloque de código para que quede así:

if sourceControl.Value <> nil then
textArea(sourceControl).SelLength = 0
textArea(sourceControl).Text = "This is a test"
end if

Observa que en este caso se utiliza un Cast o proyección de tipo a TextArea de la propiedad sourceControl para que podamos trabajar con las propiedades y métodos del control que, sabemos, es en realidad un control de tipo TextArea.

(Si te sientes perdido en alguna parte de las explicaciones, te recomiendo mi libro electrónico “Programación Multiplataforma Xojo”, donde quedan explicados de forma detallada estos y otros conceptos de Programación Orientada a Objetos desde cero.)

Aplica los cambios, ejecuta la aplicación y observarás que en esta ocasión continuará funcionando sin que se produzca su salida inesperada.

Related Posts / Entradas Relacionadas

Un comentario en “WeakRef y la gestión de memoria

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *