2016-03-26 4 views
-2

Ich arbeite an einem Multiplattform-Projekt, wo ich viele Steuerelemente dynamisch als Ergebnis einiger wichtiger Berechnungen erstellen muss. Wenn ich die Bedingungen ändere, muss ich alle dynamisch erstellten Steuerelemente entfernen und die Neuberechnungen vornehmen und schließlich die Steuerelemente erneut erstellen.Dynamische Kontrollen gibt Segmentierung Fehler (11)

Ich handle dies, indem Sie zuerst dynamisch eine TScrollBox (iOFPLayout) auf einem TTabItem erstellen. Ich verschiebe die vordefinierte Kopfzeile TToolBar von der TTabItem in die TScrollBox, indem ich deren Eltern ändern. Dann erstelle ich Arrays von TLabel, TEdit und TButton Controls auf der TScrollBox. (Ich muss mit den dynamisch erstellten Steuerelementen im Code interagieren) Dieser Teil funktioniert auf allen Plattformen einwandfrei. Wenn ich die Steuerelemente entferne benutze ich den folgenden Code.

Auf Windows x86, x64 und OS X scheint es gut zu funktionieren. Unter Android funktioniert es einwandfrei, wenn die TScrollBox zum ersten Mal erstellt und mit dynamisch erstellten Steuerelementen gefüllt wird. Nachdem die TScrollBox entfernt und neu erstellt wurde, erhalte ich einen Fehler "Zugriffsverletzung" oder "Segmentierungsfehler (11)" an einem zufälligen Punkt, wenn die dynamischen Arrays von TLabel-Steuerelementen oberhalb der TScrollBox erstellt werden.

Ich habe das Gefühl, dass dies mit ARC zu tun hat. Ich habe alles über ARC gelesen und jeden Vorschlag, den ich finden kann, getestet, aber nichts scheint zu funktionieren. Sieht jemand was falsch ist?

Hier ist ein vollständiges minimales Arbeitsbeispiel.

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' ??? Warum??? –

+0

Ich habe Application.ProcessMessages nur hinzugefügt, um zu sehen, dass die Steuerelemente während des Debuggens entfernt werden. – TheAviator

+0

Wird von uns erwartet, dass Sie versuchen, Ihr Programm anhand Ihrer Beschreibung neu zu erstellen? Ich bezweifle, dass irgendjemand das tun wird. Können wir nicht einen [MCVE] haben? –

Antwort

-1

Die einfache Antwort auf diese Frage ist DisposeOf für jede dynamisch erstellte Steuerelement aufrufen, die die TScrollBox als Elternteil hat, bevor sich DisposeOf für die TScrollBox aufrufen.

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

Sieht aus wie aus Grenzen Indexzugriff hier. Wenn du ein komplettes Programm gezeigt hättest, dann hätten wir dir sicher viel beigebracht. So wie es ist, ist das ein Durcheinander. –

+0

Ich könnte dich David missverstehen, aber wie ich es sehe, gab es keinen Out-of-bounds-Index-Zugriff. Das Problem war, dass die TScrollBox nicht wirklich zerstört wurde, bevor ich mit der Erstellung neuer Steuerelemente begann. Die Referenzzählung hat 0 nicht erreicht.Das scheint eine Situation außerhalb des Speichers verursacht zu haben. Nachdem DisposeOf für jedes dynamisch erstellte Steuerelement aufgerufen wurde, das die TScrollBox als übergeordnetes Element hatte, wurde die TScollBox endgültig zerstört. Das hat das Problem gelöst. SilverWarior hat mich in die richtige Richtung geschoben. – TheAviator

+0

Die Art und Weise, wie ich das verstanden habe, hat mein Beispielcode nicht erreicht, weil er nicht so viel Speicher wie der ursprüngliche Code verwendet hat. Deshalb war es ein wenig nutzlos, dieses Beispiel zu posten. – TheAviator

Verwandte Themen