«правильный» способ
Обычно, если форма имеет закрытые поля, которые указывают на объекты, которые вы создаете в обработчике OnCreate
(скажем, FormCreate
), и что выЕсли вы хотите быть доступным в течение всей жизни формы, вы освобождаете их в обработчике OnDestroy
формы (скажем, FormDestroy
):
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Registry;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FRegistry: TRegistry;
FBitmap: TBitmap;
FList: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FRegistry := TRegistry.Create;
FBitmap := TBitmap.Create;
FList := TStringList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FList.Free;
FBitmap.Free;
FRegistry.Free;
end;
end.
Таким образом, они будут живы в течение всей жизни вашей формы..
В некоторых случаях вы можете создавать объекты в более позднее время - или даже иметь переменные, указывающие на разные объекты в разное время - но если они принадлежат форме, вы обычно освобождаете их с помощью формыкак в этом примере.(Вспомните, что переменные-члены класса всегда инициализируются, и что вызов Free
для переменной nil
совершенно безопасен, поскольку Free
в основном делает if Assigned then Destroy
.)
Почему бы не OnClose
?
Использование обработчика OnClose
для этого не совсем безопасно, так как он может вызываться несколько раз в течение жизни формы.И если вы введете X.Free
, вы получите X
, не являющийся nil
указателем на мусор.
Например, следующий код является ошибкой:
// BUG!! Don't do this!
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FList.Free;
Action := caNone;
end;
Попробуйте дважды закрыть форму.
Даже если вы не используете caNone
, возможно, это форма, которая открывается и закрывается несколько раз в течение ее жизни;тогда вы можете не захотеть освобождать все его объекты при первом закрытии.(И вы конечно не хотите освобождать их, не устанавливая указатели на nil
!)
Бонусная болтовня
Если вы позволитеВаше поле указывает на разные объекты в разное время, вы должны убедиться, что вы «переопределяете» поле безопасным способом.Например, следующий подход плох:
procedure RecreateFrog;
begin
FFrog.Free;
FFrog := TFrog.Create(ftBig, clRed, 123);
end;
Причина в том, что конструктор TFrog.Create
может завершиться ошибкой (вызвать исключение), и в этом случае вы получите FFrog
не- nil
указатель на мусор.Вместо этого более безопасный способ -
procedure RecreateFrog;
begin
FreeAndNil(FFrog);
FFrog := TFrog.Create(ftBig, clRed, 123);
end;
, и в этом случае FFrog
будет указателем nil
, если новый объект лягушки не может быть создан.И, конечно, в подобных ситуациях вы всегда проверяете, что FFrog
назначается каждый раз, когда вы хотите использовать текущую лягушку.
Конечно, есть другие способы сделать что-то, и иногда у вас есть конструкторычто вы никогда не ошибетесь и т. д. Основное правило заключается в том, что вы должны знать, что вы делаете, и что код должен быть гарантированно никогда не пропускать какие-либо ресурсы, получать доступ к висящим указателям и т. д.