11

if Form.Release is called after using the form, it will free all related memory but not set the form variable to nil.

if not assigned (Form1) then
  begin
    Application.CreateForm(Tform1, Form1);
    try
      // Do something
    finally
      Form1.Release
    end;
  end;

To be able to call the same code again, Form1 would have to be set to nil at some point. From the description of Release I cannot do

Form1 := nil;

right after Release, because the Release procedure will return directly after being called and before the form is actually freed. I cannot detect when Form.Release is finished to set the form var to nil.

What is the best way to do this?

Gabriel
  • 20,797
  • 27
  • 159
  • 293
Holgerwa
  • 3,430
  • 9
  • 42
  • 50
  • related: https://stackoverflow.com/questions/916843/is-it-safe-to-use-free-instead-of-release-for-modal-forms-in-delphi – Gabriel Nov 30 '18 at 09:56
  • Careful with Application.CreateForm. the first form created with that method sets that form as the main form. So make sure you use it FIRST for your main form. After that you can use it on other forms also. – Gabriel Nov 16 '22 at 11:24

5 Answers5

17

Put the line

  Form1 := nil;  

just after the call to Release.

Release is just posting a CM_RELEASE message to the Form which allows the Form to finish what's in its queue (event handlers) before handling the CM_RELEASE message which means normally just calling Free.
So, after calling Release, you should not assume that the Form variable still points to a valid Form, thus putting nil into the variable.

11

Release is just a (potentially) deferred Free. The 1st thing you should do after calling Release is nilling the variable.
Then, you'll be safe even if some code tries to reference Form1 before it is actually destroyed. In a case like in your code, it would just safely recreate another Form1 for the new usage without bothering the one being destroyed.

Barry Kelly
  • 41,404
  • 5
  • 117
  • 189
Francesca
  • 21,452
  • 4
  • 49
  • 90
4

Of you could just always call this:

procedure FreeOrReleaseAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  if Temp is TCustomForm then
    TCustomForm(Temp).Release
  else
    Temp.Free;
end;

Be sure to check the type after casting to a TObject as you can't test the type of Obj. This should be safe since like Free, Release is non-virtual.

Jim McKeeth
  • 38,225
  • 23
  • 120
  • 194
2

As is mentioned Release is only a deferred Free for a form to use if it wants to Close/Free itself. Other then being deferred it does nothing different from Release. So there is no use in calling Release in that example. Calling Free seems to be more logical. And you can set it to nil after calling Free or use FreeAndNil.

If you still want to use Release that is fine. Just setting the variable value to nil works. Doing that does not make the forum behave differently. But remember that in this case it is more efficient and more deterministic to call Free instead of Release. My preference is to only use Release where is really needed.

Lars Truijens
  • 42,837
  • 6
  • 126
  • 143
1

In Delphi Win32, the appropriate way to free objects is to call

FreeAndNil(Form1)

This does both jobs in a single call.

However, I have a sneaking feeling there's more to your question than meets the eye. Are you using Delphi for .NET - and if so, which version?

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • Roddy, I am using Delphi Win32 (sorry for not mentioning). As far as I understood, for a form Release does a lot more tasks than just a plain FreeAndNil, which would not free components owned by the form. Is this correct? – Holgerwa Nov 08 '08 at 09:24
  • Yes, Release does more, but only to defer the calling of Free. You don't need to call Free deferred, so you don't need to call Release and can call Free. Also see http://stackoverflow.com/questions/274523/formrelease-nil#274734 – Lars Truijens Nov 08 '08 at 13:48