2016-03-26 10 views
-2

私はいくつかの主要な計算の結果として動的にたくさんのコントロールを作成しなければならないマルチプラットフォームプロジェクトに取り組んでいます。条件を変更するときは、動的に作成されたすべてのコントロールを削除して、再計算を行い、最後にコントロールを再度作成する必要があります。ダイナミックコントロールはセグメント化エラーを発生させます。(11)

私はまず、TTabItemの上にTScrollBox(iOFPLayout)を動的に作成します。私は事前定義されたヘッダーTToolBarを、その親を変更することによって、TTabItemからTScrollBoxに移動します。次に、TScrollBoxにTLabel、TEdit、TButtonコントロールの配列を作成します。 (私はコードで動的に作成されたコントロールと対話する必要があります)この部分はすべてのプラットフォームで正常に動作します。コントロールを削除すると、以下のコードが使用されます。

Windows x86、x64、およびOS Xでは正常に動作しているようです。 AndroidではTScrollBoxが初めて作成され、動的に作成されたコントロールでいっぱいになります。 TScrollBoxが削除され、再作成された後、TLabelコントロールの動的配列がTScrollBoxの上に作成されると、ランダムアクセスポイントで「アクセス違反」または「セグメンテーションフォールト(11)」というエラーが発生します。

これはARCと関連があると感じています。私はARCに関するすべてのことを読んだことがありますが、私が見つけることができるすべての提案をテストしましたが、何も動作していないようです。誰が何が間違っているのを見ますか?

procedure TTabbedForm.RemoveOFP(); 
begin 
    // Move the ToolBar2 back to TabItem3 so it won’t get destroyed 
    ToolBar2.Parent := TabItem3; 
    if Assigned(iOFPLayout) then 
    begin 
    // iOFPLayout holds a lot of dynamically created controls 
    iOFPLayout.Release; 
    iOFPLayout.DisposeOf; 
    iOFPLayout := nil; 
    Application.ProcessMessages; 
    end; 
end; 

ここには完全な最小限の動作例があります。

unit Unit1; 

interface 

uses 
    System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
    FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Controls.Presentation, FMX.Layouts; 

type 
    TMainForm = class(TForm) 
    ToolBar1: TToolBar; 
    Create: TButton; 
    Destroy: TButton; 
    procedure CreateClick(Sender: TObject); 
    procedure DestroyClick(Sender: TObject); 
    private 
    sb: TScrollBox; 
    lbl: array of TLabel; 
    end; 

var 
    MainForm: TMainForm; 

implementation 

{$R *.fmx} 

procedure TMainForm.CreateClick(Sender: TObject); 
var 
    i: Integer; 
begin 
    // Create a TScollBox on the MainForm 
    sb := TScrollBox.Create(Self); 
    sb.Align := TAlignLayout.Client; 
    sb.ShowScrollBars := True; 
    sb.Parent := MainForm; 
    // Set up the number of labels to put on sb 
    SetLength(lbl, 1000); 
    // Create these labels and set some properties 
    for i := Low(lbl) to High(lbl) do 
    begin 
    // On first run on Android devices this causes no problems. 
    // After DestroyClick has been run after the first CreateClick then 
    // I get "Access violation/Segmentation fault (11) here. 
    // It happens after about 800+ labels has been created. 
    lbl[i] := TLabel.Create(sb); 
    lbl[i].Text := 'Label ' + IntToStr(i); 
    lbl[i].Position.X := 10; 
    lbl[i].Position.Y := i * 20; 
    lbl[i].Parent := sb; 
    end; 
end; 

procedure TMainForm.DestroyClick(Sender: TObject); 
begin 
    if Assigned(sb) then 
    begin 
    sb.Release; 
    sb.DisposeOf; 
    sb := nil; 
    end; 
end; 
end. 
+1

'Application.ProcessMessages' ???なぜ??? –

+0

私はApplication.ProcessMessagesを追加して、デバッグ中にコントロールが削除されるのを見ました。 – TheAviator

+0

あなたの説明からあなたのプログラムを作り直すことを期待していますか?私は誰もそれをすることを疑う。 [mcve]はできませんか? –

答えて

-1

この質問に対する簡単な答えはTScrollBox自身のためDisposeOfを呼び出す前に、親としてTScrollBoxを持つ各動的に作成制御のためのDisposeOfを呼び出すことです。

procedure TMainForm.DestroyClick(Sender: TObject); 
var 
    i: Integer; 
begin 
    if Assigned(sb) then 
    begin 
    // First call DisposeOf for each child control 
    for i := Low(lbl) to High(lbl) do 
    begin 
     lbl[i].DisposeOf; 
    end; 
    // Then call DisposeOf for the parent control 
    sb.Release; 
    sb.DisposeOf; 
    sb := nil; 
    end; 
end; 
+0

ここではインデックスへのアクセスを制限します。あなたがフルプログラムを見せてくれたら、私はあなたに十分なことを教えてくれるはずだったと確信しています。それはそのままですが、これは混乱です。 –

+0

私はデビッドを誤解するかもしれませんが、私が見ているように、インデックスアクセスは範囲外です。問題は、新しいコントロールの作成を開始する前にTScrollBoxが実際に破棄されなかったことです。参照カウントは0に達しませんでした。それは記憶不足の状況を引き起こしたようです。 DisposeOfが親としてTScrollBoxを持つ動的に作成されたコントロールごとに呼び出された後、TScollBoxは最終的に破棄されました。それが問題を解決しました。 SilverWariorは正しい方向に私を押し込んだ。 – TheAviator

+0

元のコードと同じくらい多くのメモリを使用していなかったため、私のサンプルコードは理解できませんでした。だから、そのサンプルを投稿するのはちょっと役に立たなかったのです。 – TheAviator

関連する問題