5

Delphi XE7 Update 1 および Delphi XE8 でテスト済み

Windows OS (7 SP1 x64)、MACOSX (10.10.3)、および Android (5.0.2) で注文を作成します。

    "class constructor TGlobalClass.Create;" -> "constructor TfmMain.Create;" -> "procedure TfmMain.FormCreate(Sender: TObject);"

Windows OS および 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.
4

3 に答える 3

5

デスクトップ コンパイラ

アプリケーション オブジェクトがそのコンポーネントを破棄すると、メイン フォームが破棄されます。それFMX.FormsDoneApplication手続きの中で起こります。

procedure DoneApplication;
begin
  if Screen <> nil then
    Screen.ActiveForm := nil;
  Application.DestroyComponents;  <-- this is destroying your main form
end;

シャットダウン中に終了プロシージャDoneApplicationとして呼び出されます。その exit proc は次のTApplication.Runように登録されます。

{$IFNDEF ANDROID}
  AddExitProc(DoneApplication);
{$ENDIF}

クラス コンストラクターは、それらを定義するユニットの初期化セクションから呼び出されます。したがって、TGlobalClass.Createの初期化から呼び出されますuClassVar。クラス デストラクタは、同じユニットのファイナライズ セクションから呼び出されます。

システムのシャットダウンは、 のSystemユニットによって実行され_Halt0ます。ユニットのファイナライズを実行する前に、すべての終了プロシージャを実行します。したがって、フォームはクラス デストラクタが呼び出される前に破棄されます。

モバイル コンパイラ

DoneApplicationAndroid では単に呼び出されないことに注意してください。

{$IFNDEF ANDROID}
  AddExitProc(DoneApplication);
{$ENDIF}

これは、メイン フォームの破棄がユニットのファイナライズから呼び出されていることを意味します。各ユニットがファイナライズされると、そのファイナライズ セクションが実行され、グローバル変数がスコープを離れます。最終的に、メイン フォームへの参照がなくなるため、そのデストラクタが実行されます。

前述のように、クラス デストラクタはユニットのファイナライズからも呼び出されます。uClassVarAndroid では、メイン フォームが破棄される前にクラス デストラクタが実行されるため、メイン フォームの最終参照が解放される前にクラスがファイナライズされることは明らかです。

uClassVarは初期化順序の最後のユニットであり、したがって最終化順序の最初のユニットであるため、これは完全に理にかなっています。後で確実にファイナライズしたい場合はuClassVar、より早く初期化できるように手配する必要があります。たとえば、.dpr ファイルの uses 句を次のように変更します。

uses
  uClassVar in 'uClassVar.pas',  
  System.StartUpCopy,
  FMX.Forms,
  ufmMain in 'ufmMain.pas' {fmMain};

現在uClassVarは初期化された最初のユニットであり、したがって最後にファイナライズされたユニットです。

于 2015-06-26T09:54:06.143 に答える
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.

ユニット2:

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 を使用するため、最初にファイナライズされません。そのため、初期化順序は「期待される」ものとは異なります。

出力は次のとおりです。

Begin
Unit2.Destroy
TUnit1.Destroy
TUnit2.Destroy

そのような場合、モバイルコンパイラが何か違うことをする理由がわかりません...

于 2015-06-26T10:49:22.730 に答える
-1

DisposeOf無料コンポーネントを使用しています

.Freeasまたはを使用しないでください.Destroy

例:

Scrollbox1.Components[1].DisposeOf;  
于 2015-09-22T06:49:55.487 に答える