在Windows操作系统(7 SP1 x64),MACOSX(10.10.3)和Android(5.0.2)上创建订单:
"class constructor TGlobalClass.Create;" -> "constructor TfmMain.Create;" -> "procedure TfmMain.FormCreate(Sender: TObject);"
Windows操作系统和MACOSX上的下达订单:
"TfmMain.FormDestroy" -> "destructor TfmMain.Destroy" -> "class destructor TGlobalClass.Destroy;"
Android上的发布订单:
"class destructor TGlobalClass.Destroy;" -> "TfmMain.FormDestroy" -> "destructor TfmMain.Destroy"
问题是:为什么Android平台上的CLASS VAR在主窗体之前发布?
代码示例:
unit uClassVar;
interface
type
TGlobalClass = class
class var F1: Integer;
class constructor Create;
class destructor Destroy;
end;
implementation
{ TX }
class constructor TGlobalClass.Create;
begin
{ Breakpoint there }
F1 := 100;
end;
class destructor TGlobalClass.Destroy;
begin
{ Breakpoint there }
F1 := 200;
end;
end.
主要单位:
unit ufmMain;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics;
type
TfmMain = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
fmMain: TfmMain;
z: Integer;
implementation
uses
uClassVar;
{$R *.fmx}
constructor TfmMain.Create;
begin
{ Breakpoint there }
inherited;
end;
destructor TfmMain.Destroy;
begin
{ Breakpoint there }
inherited;
end;
procedure TfmMain.FormCreate(Sender: TObject);
begin
{ Breakpoint there }
TGlobalClass.F1 := -99999;
end;
procedure TfmMain.FormDestroy(Sender: TObject);
begin
{ Breakpoint there }
z := 200;
end;
end.
项目文件:
program ClassVar;
uses
System.StartUpCopy,
FMX.Forms,
ufmMain in 'ufmMain.pas' {fmMain},
uClassVar in 'uClassVar.pas';
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TfmMain, fmMain);
Application.Run;
end.
答案 0 :(得分:5)
Desktop compilers
Your main form is destroyed when the application object destroys its components. That happens in FMX.Forms
in the DoneApplication
procedure.
procedure DoneApplication;
begin
if Screen <> nil then
Screen.ActiveForm := nil;
Application.DestroyComponents; <-- this is destroying your main form
end;
And DoneApplication
is called during shutdown as an exit proc. That exit proc is registered from TApplication.Run
like this:
{$IFNDEF ANDROID}
AddExitProc(DoneApplication);
{$ENDIF}
Class constructors are called from the initialization section of the unit which defines them. So, TGlobalClass.Create
is called from the initialization of uClassVar
. Class destructors are called from the finalization section of that same unit.
The system shutdown is performed by the System
unit in _Halt0
. It executes all the exit procs before performing unit finalization. Hence your form is destroyed before the class destructors are called.
Mobile compilers
Note that DoneApplication
is simply not called on Android.
{$IFNDEF ANDROID}
AddExitProc(DoneApplication);
{$ENDIF}
This means is that the main form's destruction is being invoked from unit finalization. As each unit is finalized, its finalization sections are executed which result in any global variables leaving scope. Eventually, there are no more references to your main form and so its destructor is executed.
As discussed above, the class destructors are also called from unit finalization. Since on Android, your class destructor executes before the main form is destroyed, it is clear to see that uClassVar
is finalized before the main form's final reference is released.
Now, that makes perfect sense because uClassVar
is the final unit in the initialization order, and hence the very first unit in the finalization order. If you wanted to ensure that uClassVar
is finalized later, you need to arrange for it to be initialized sooner. For instance, by changing the uses clause of your .dpr file like so:
uses
uClassVar in 'uClassVar.pas',
System.StartUpCopy,
FMX.Forms,
ufmMain in 'ufmMain.pas' {fmMain};
Now uClassVar
is the first unit initialized, and hence the last unit finalized.
答案 1 :(得分:0)
该计划:
program Destructors;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Unit1 in 'Unit1.pas',
Unit2 in 'Unit2.pas';
var
X: TUnit1;
begin
x := TUnit1.Create;
x.Free;
Writeln('Begin');
end.
1单元:
unit Unit1;
interface
uses
System.Classes, Unit2;
type
TUnit1 = class
public class var
X: TUnit2;
public
class constructor Create;
class destructor Destroy;
destructor Destroy; override;
end;
implementation
{ TUnit1 }
class constructor TUnit1.Create;
begin
X := TUnit2.Create;
end;
class destructor TUnit1.Destroy;
begin
X.Free;
Writeln('TUnit1.Destroy');
end;
destructor TUnit1.Destroy;
begin
Writeln('Unit1.Destroy');
inherited;
end;
end.
UNIT2:
unit Unit2;
interface
uses
System.Classes;
type
TUnit2 = class
public class var
X: TComponent;
public
class constructor Create;
class destructor Destroy;
destructor Destroy; override;
end;
implementation
{ TUnit2 }
class constructor TUnit2.Create;
begin
X := TComponent.Create(nil);
X.Name := ClassName;
end;
class destructor TUnit2.Destroy;
begin
X.Free;
Writeln('TUnit2.Destroy');
end;
destructor TUnit2.Destroy;
begin
Writeln('Unit2.Destroy');
inherited;
end;
end.
包含Unit2作为项目文件中的最后一个单元,但由于Unit1使用Unit2,因此它不会首先完成 - 因此初始化顺序与&#34;期望的&#34;不同。
输出如下:
Begin
Unit2.Destroy
TUnit1.Destroy
TUnit2.Destroy
我不确定为什么在这种情况下移动编译器会做一些不同的事情......
答案 2 :(得分:-1)
您正在使用DisposeOf
免费组件
请勿使用.Free
或.Destroy
示例:
Scrollbox1.Components[1].DisposeOf;