Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 12-10-2005
CelestronFan CelestronFan is offline
Miembro
 
Registrado: oct 2005
Posts: 14
Poder: 0
CelestronFan Va por buen camino
Uso de nil

Saludos a todos,

Por favor, alguien podría explicarme brevemente que significa el nil?

Normalmente yo acostumbro a poner por ejemplo:

Código Delphi [-]
     SerialPort.Caption := 'Connected';

pero veo a menudo que los ejemplos y la ayuda coloca:

Código Delphi [-]
   if SerialPort <> nil then
       SerialPort.Caption := 'Connected';

En realidad no entiendo para que es esa comparación con nil.

Gracias.
Responder Con Cita
  #2  
Antiguo 12-10-2005
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

La palabra reservada "nil" indica en Delphi una dirección indeterminada en la memoria. Vale asignar "nil" a un puntero, de manera que este no apunte a ninguna dirección de memoria en concreto. Una variable cuya referencia es un tipo de clase es en realidad un puntero que referencia a determinado objeto, de ahí que pueda asignarse también a este tipo de variables "nil".

En el caso que te ocupa se está preguntando (más o menos) lo siguiente: "¿SerialPort apunta a alguna dirección de memoria en concreto? Sí es así, ejecútese la instrucción siguiente; si no es así deje de ejecutarse la misma". Lo mismo no me expliqué correctamente pero eso tengo yo entendido que significa la palabra reservada "nil".

Por poner un ejemplo, cuando se destruye un determinado objeto su variable no apuntará ya a la dirección de memoria en que se hacía referencia (si alguna vez fue instanciada la clase de objeto en cuestión) a dicho objeto, y, por lo tanto, la variable de marras será "nil".
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #3  
Antiguo 12-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Cita:
Empezado por dec
Por poner un ejemplo, cuando se destruye un determinado objeto su variable no apuntará ya a la dirección de memoria en que se hacía referencia (si alguna vez fue instanciada la clase de objeto en cuestión) a dicho objeto, y, por lo tanto, la variable de marras será "nil".
Si usamos Objeto.Free la variable Objeto se queda con la dirección de memoria donde estaba creada la variable, por ende, es mejor usar siempre FreeAndnil(Objeto) para que se quede apuntando a nil.

Tambien el código:
Código Delphi [-]
 if SerialPort <> nil then
       SerialPort.Caption := 'Connected';
se puede traducir como: ¿el Objeto SerialPort ha sido creado previamente?:
- Si, por tanto se puede acceder a su propiedad Caption, así que la modificamos.
- No, entonces, si intentamos acceder a una propiedad (Caption en este caso) que en realidad no existe en memoria, estamos traspasando un puntero nulo y obtendríamos un Access Violation.

Como se puede apreciar, es una pregunta de seguridad. Al tiempo de destruir el objeto SerialPort, seguro que pone FreeAndnil(SerialPort).

Resumiendo:
- Si declaramos una variable que desciende de Tobject, como valor primario debe tener nil (delphi ya lo hace por nosotros), aunque yo prefiero poner Objeto := nil (para clarificar el código)
- Cuando vamos a crear el objeto, miramos si tiene nil:
  1. Si tiene nil, creamos el objeto.
  2. Si no tiene nil, significa que ya ha sido creado, por tanto accedemos a él.

Las funciones Assigned y FreeAndnil nos ayudan bastante en nuestro código:

Assigned(objeto) es identico a poner if Objeto <> nil then
Código Delphi [-]

private 
  nodo:TTreeNode;
end;

implementation

// inicializamos el valor de nodo
procedure TForm1.Form1Create;
begin
  nodo := nil;
end;

// accedemos al nodo o lo creamos si es necesario
procedure TForm1.button1Click;
begin
  if assigned(nodo) then 
    nodo.text:= 'si ';
  else
    nodo := TTreenode.Create(self);
end;

// al salir liberamos el nodo
// si tienen nil no hace nada
// si ha sido creado, lo libera
procedure Tform1.FormClose;
begin
  freeandnil(nodo);
end;

saludos
Responder Con Cita
  #4  
Antiguo 12-10-2005
Avatar de lucasarts_18
lucasarts_18 lucasarts_18 is offline
Miembro
 
Registrado: mar 2005
Ubicación: Villa Alemana,Chile
Posts: 1.087
Poder: 21
lucasarts_18 Va por buen camino
Hola.

Aquí dejo otro ejemplo:

Código Delphi [-]
 procedure TFrmInterfaz.PageControlChange(Sender: TObject);
 begin
   if PageControl.ActivePage <> TabSheet3 then
   begin
     if Assigned(InterfEntrada) then
        //como dice Lepe es lo mismo que if InterfEntrada <> nil
     begin
       DS.DataSet := nil;
       FreeAndNil(InterfEntrada);
     end;
   end
   else
     if PageControl.ActivePage = TabSheet3 then
       try
         InterfEntrada :=  TOracleDataset.Create (nil);
         InterfEntrada.Session := DMServidores.OSession;
       except
         InterfEntrada.Free;
       end;
 end;

En definitiva, la comparación de un objeto con nil es para saber si existe y si tiene una dirección de memoria asignada.

Hasta luego..
__________________
No todo es como parece ser...
Responder Con Cita
  #5  
Antiguo 12-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Cuidado con ese código, no es standard (lo digo por otro hilo que habla de stardares )

el TOracleDataset.Create está dentro del bloque try, esto quiere decir que si se produce una excepción al tiempo de crear ese objeto, irá al bloque except, e intentará liberar un objeto que aún no se ha creado. Además no se usa FreeAndNil en el except, así que de nada nos servirá Assigned.

Código propuesto:
Código Delphi [-]
 procedure TFrmInterfaz.PageControlChange(Sender: TObject);
 begin
   if PageControl.ActivePage <> TabSheet3 then
   begin
     if Assigned(InterfEntrada) then
        //como dice Lepe es lo mismo que if InterfEntrada <> nil
     begin
       DS.DataSet := nil;
       FreeAndNil(InterfEntrada);
     end;
   end
   else
// Si no es distinto, es que es igual, quitamos la pregunta
//     if PageControl.ActivePage = TabSheet3 then
   begin
       InterfEntrada :=  TOracleDataset.Create (nil);
       try
         InterfEntrada.Session := DMServidores.OSession;
       except
         freeandnil(InterfEntrada);
       end;
   end;
 end;
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #6  
Antiguo 12-10-2005
Avatar de lucasarts_18
lucasarts_18 lucasarts_18 is offline
Miembro
 
Registrado: mar 2005
Ubicación: Villa Alemana,Chile
Posts: 1.087
Poder: 21
lucasarts_18 Va por buen camino
Hola:

Lepe, Sinceramente tienes toda la razón .

Saludos..

__________________
No todo es como parece ser...
Responder Con Cita
  #7  
Antiguo 12-10-2005
CelestronFan CelestronFan is offline
Miembro
 
Registrado: oct 2005
Posts: 14
Poder: 0
CelestronFan Va por buen camino
Bueno, muchas gracias por la explicación tan detallada.

A ver si estoy en lo correcto, en conclusión nil, Assigned y Freeandnil se usan para corroborar si el objeto sobre el que se va a actuar está creado en memoria y en caso contrario actuar sobre la excepción que se generaría.

Entonces mi pregunta es, en lugar del nil ¿Se puede usar un bloque de este tipo?
Código:
 Try  
   sentencias... 
 Except 
   sentencias... 
 Finally o Raise 
   sentencias... 
 end
Es decir (usando el ejemplo de Lepe) podría hacer algo como esto?:

Código Delphi [-]
  private 
   nodo:TTreeNode;
 end;
 implementation
 
 // inicializamos el valor de nodo
 //procedure TForm1.Form1Create;
 //begin
 //  nodo := nil;
 //end;
 
 // accedemos al nodo o lo creamos si es necesario
 procedure TForm1.button1Click;
 begin
    Try
        nodo.text:= 'si ';
    Except
        nodo := TTreenode.Create(self);
        nodo.text:= 'si ';
  end;
 end;
 
 // al salir liberamos el nodo
 // si tienen nil no hace nada
 // si ha sido creado, lo libera
 
 procedure Tform1.FormClose;
 begin
   freeandnil(nodo);
 end;
La idea no es evitar manejar el nil, sino entender bien como hacerlo y saber si este tipo de casos se puede tratar como una excepción cualquiera.

Aunque me parece que no, porque haría lo indicado para cualquier tipo de excepción y no solo cuando el objeto no exista....

Si el control que estoy manejando pertenece a la forma principal de mi programa (me refiero a un control normal, que no se cree a posteriori en runtime) entonces no tendría sentido usar el nil, pues todos los controles de la forma se crean y asignan en memoria con Application.CreateForm(...
antes de que delphi ejecute Application.run,

...o ¿es que no he entendido que un control puede estar mostrado en una forma pero no asignado a memoria?

Gracias.
Responder Con Cita
  #8  
Antiguo 13-10-2005
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,


Cita:
Empezado por CelestronFan
(...) en conclusión nil, Assigned y Freeandnil se usan para corroborar si el objeto sobre el que se va a actuar está creado en memoria y en caso contrario actuar sobre la excepción que se generaría.
Bueno. Yo diría que hay que matizar. "nil" puede usarse con los operadores de relación, tal como queda dicho más arriba. "Assigned" puede usarse en sentencias condicionales. "FreeAndNil" sirve para liberar un determinado objeto y hacer que la variable que guardara su referencia no apunte a ningún sitio en concreto. Pero no hay que actuar sobre excepción alguna, en mi opinión, puesto que lo siguiente no tiene porqué generar ninguna excepción.

Código Delphi [-]
 if Objeto <> nil then
   {...}
 else
   {...}
Cita:
Empezado por CelestronFan
Entonces mi pregunta es, en lugar del nil ¿Se puede usar un bloque de este tipo?

Código:
 Try
   sentencias...
 Except
   sentencias...
 Finally o Raise
   sentencias...
 end
Creo que de lo de arriba lo que se ve extraño es el "Finaly o Raise". Pudiera ser que estuvieras refiriéndote a "Finally o Except".


Cita:
Empezado por CelestronFan
Es decir (usando el ejemplo de Lepe) podría hacer algo como esto?:

Código Delphi [-]
 // accedemos al nodo o lo creamos si es necesario
 procedure TForm1.button1Click;
 begin
   Try
     nodo.text:= 'si ';
   Except
     nodo := TTreenode.Create(self);
     nodo.text:= 'si ';
   end;
 end;
No es del todo correcto, me parece a mí. Me explicaré. Se intenta asignar determinado valor a cierta propiedad del objeto "nodo": ya aquí, si no estás seguro de que "nodo" esté disponible deberías comprobar con un "if Assigned(nodo) then ..." o un "if nodo <> nil then ..." que esto es así. Si el objeto no estuviera disponible, tal como lo haces más arriba, evidentemente se produciría una excepción, que capturarías, y entonces crearías el objeto "nodo" y asignarías a su propiedad "Text" determinado valor... pero no creo que halla que llevar ahí, puesto que, como digo arriba, bastaría con comprobar si el objeto está creado o no lo está antes de asignar a su propiedad un determinado valor, o crearlo antes y hacerlo luego, si fuera menester.


Cita:
Empezado por CelestronFan
La idea no es evitar manejar el nil, sino entender bien como hacerlo y saber si este tipo de casos se puede tratar como una excepción cualquiera.
Capturar la excepción que se produciría, efectivamente, podrías capturarla, creo yo, pero, ciertamente, creo que lo suyo es hacerlo como arriba se dice, mediante una sentencia condicional en donde se comprobara la disponibilidad del objeto en cuestión.


Cita:
Empezado por CelestronFan
Aunque me parece que no, porque haría lo indicado para cualquier tipo de excepción y no solo cuando el objeto no exista....
Así es. Pero, además, insisto en que no veo la necesidad de hacerlo de ese modo, pudiéndose hacer como se dice arriba: creo que también se ganaría en legilibidad del código fuente. Y puede que hubiera otras razones por las que no sería recomendable hacer algo así. Se me ocurre que una vez entraras en la excepción... las siguientes instrucciones del procedimiento no se ejecutarían debidamente... aquí creo que me lío un poco y no sé explicarme o no lo tengo del todo claro. Te pido disculpas.


Cita:
Empezado por CelestronFan
Si el control que estoy manejando pertenece a la forma principal de mi programa (me refiero a un control normal, que no se cree a posteriori en runtime) entonces no tendría sentido usar el nil, pues todos los controles de la forma se crean y asignan en memoria con Application.CreateForm(... antes de que delphi ejecute Application.run, ...o ¿es que no he entendido que un control puede estar mostrado en una forma pero no asignado a memoria?
No; has entendido bien, creo yo. Si tú no liberas un control que se muestra en una "forma" "desde su creación", este estará disponible y su referencia también lo estará. Si liberaras el control perderías su referencia y el mismo también dejaría de mostrarse en la "forma". Puedes probarlo. Sitúa dos botones en un formulario y, desde uno de ellos libera al otro: verás cómo desaparece el formulario.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #9  
Antiguo 13-10-2005
CelestronFan CelestronFan is offline
Miembro
 
Registrado: oct 2005
Posts: 14
Poder: 0
CelestronFan Va por buen camino
Gracias dec y a todos.

Quedó superclaro. Lo que más me cuesta del delphi es cambiar el modo de pensar durante la programación, y eso que me dediqué a hacer una flujograma para mi proyectito pero a pesar de eso me vuelvo un pastel con los objetos a veces. Bueno, con el tiempo y sus excelentes ayudas lo voy a superar....

Muchas Gracias.
Responder Con Cita
  #10  
Antiguo 13-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Resumiendo sería: "Mas vale prevenir que curar"

Como bien has dicho, la excepción tambien puede ocurrir por otra causa; asumir que se ha producido porque el objeto no esté creado, es demasiado

Cita:
Empezado por CelestronFan
pues todos los controles de la forma se crean y asignan en memoria con Application.CreateForm(...
antes de que delphi ejecute Application.run,
El form Si se crea con Application.CreateForm, por tanto, pertenece a application y application se encargará de liberarlo.

Un TEdit, colocado en el form1, pertenece al Form, por tanto, al cerrar la aplicación:
- Application manda destruir a todos los Forms que contiene.
- Form1 manda a destruir todos los controles que contiene, entre ellos el Edit

De ahí que todos los objetos que son contenedores, TForm, Tpanel, etc, tengan la propiedad Components y ComponentsCount que es una lista de los controles que ha liberar ese objeto, y el orden en el que se crearon.
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 07:18:45.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi