This depends entirely on how the form is used.
Modal forms
The simplest case is when the form is modal. Then you typically use the following idiom:
procedure TForm1.btnFrogPropertiesClick(Sender: TObject);
var
Frm: TFrogPropertiesForm;
begin
Frm := TFrogPropertiesForm.Create(Self);
try
Frm.ShowModal;
finally
Frm.Free;
end;
end;
Or, if you want to do some special processing if the user closes the dialog box by clicking the OK button (and not the Cancel button):
procedure TForm1.btnFrogPropertiesClick(Sender: TObject);
var
Frm: TFrogPropertiesForm;
begin
Frm := TFrogPropertiesForm.Create(Self);
try
if Frm.ShowModal = mrOk then
UpdateFrog;
finally
Frm.Free;
end;
end;
Notice that I use Self as owner in both cases. That isn't necessary for the sake of ownership, since -- quite obviously -- we free the forms as soon as they are closed. But I often use Self anyway, because I tend to use Position = poOwnerFormCenter for my dialogs.
Independent windows that are freed when you close them
Another particularly simple case is when you dynamically create (possibly multiple) instances of a form class and want to display them on-screen in a non-modal fashion until the user closes them, in which case the instances are freed. If so, it is really simple:
procedure TForm1.Button1Click(Sender: TObject);
var
ImageViewer: TImageViewerFrm;
begin
ImageViewer := TImageViewerFrm.Create(nil);
ImageViewer.Image := 'flower.jpg';
ImageViewer.Show;
end;
assuming it has a public property named Image that takes the file name of an image file to display.
This will create and show the form when you click the button. To make sure it is freed when you close it, just add an OnClose handler to the TImageViewerFrm and set the Action parameter to caFree:
procedure TImageViewerFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
Using this approach, you can create any number of image viewer forms with different images, and they will all live until the user closes them, or until the application is terminated.
Other approaches
Of course, there are many more possible scenarios, and, therefore, many more possible solutions. In some cases you might want to have full control over the forms of a particular type, and so you store them in an array. It is fine to free them using MyForm.Free or FreeAndNil(ImageForms[4]).
FreeAndNil(X) effectively does X.Free; X := nil (but in a safer manner), that is, it sets the variable to nil after it has freed the object it used to point to. That way you avoid a dangling pointer. In some cases, you must do this. (But now I am digressing. This applies to Delphi objects in general, and has nothing to do with forms in particular.)
But in Delphi you never free an object (a form or not) by writing X.Destroy. You use X.Free which effectively does if X <> nil then X.Destroy.
If you want to learn more about this, I strongly recommend buying a good textbook about Delphi programming. There's no more efficient way of really learning it.