2016-03-26 64 views
-2

Bazı büyük hesaplamaların sonucu olarak dinamik olarak çok sayıda denetim oluşturmam gereken bir çoklu platform projesi üzerinde çalışıyorum. Koşulları değiştirirken, dinamik olarak oluşturulmuş tüm denetimleri kaldırmalı ve yeniden hesaplamaları yapmalı ve sonunda denetimleri yeniden oluşturmam gerekir.Dinamik denetimler, Segmentasyon hatası verir (11)

Bunu ilk olarak dinamik olarak bir TTabItem'in üstünde bir TScrollBox (iOFPLayout) oluşturun. Ön tanımlı üstbilgi TToolBar'ı, üst öğeyi değiştirerek TTabItem'den TScrollBox'a taşıyorum. Ardından TScrollBox'ta TLabel, TEdit ve TButton kontrol dizileri oluşturuyorum. (Kodda dinamik olarak oluşturulmuş kontrollerle etkileşime girmem gerekiyor) Bu bölüm tüm platformlarda iyi çalışıyor. Kontrolleri kaldırdığımda aşağıdaki kodu kullanıyorum.

Windows x86, x64 ve OS X'de iyi çalışıyor gibi görünüyor. Android'de TScrollBox ilk oluşturulduğunda ve dinamik olarak oluşturulmuş kontrollerle doldurulduğunda iyi çalışıyor. TScrollBox kaldırıldıktan ve yeniden oluşturulduktan sonra, TScrollBox'un üstünde TLabel denetimlerinin dinamik dizileri oluşturulduğunda rasgele bir noktada “Erişim İhlali” veya “Segmentasyon hatası (11)” hatası alıyorum.

Bunun ARC ile ilgili olduğunu hissediyorum. ARC ile ilgili her şeyi okudum ve bulabildiğim her şeyi test ettim ama hiçbir işe yaramadı. Herkes neyin yanlış olduğunu görüyor mu?

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; 

İşte tam bir örnek çalışma örneği.

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' ??? Niye ya??? –

+0

Sadece denetimleri hata ayıklama sırasında kaldırıldığını görmek için Application.ProcessMessages ekledim. – TheAviator

+0

Programınızı açıklamanızdan yeniden oluşturmayı denememiz bekleniyor mu? Bunu yapacak biri olduğundan şüpheliyim. [Mcve] 'ye sahip olamaz mıyız? –

cevap

-1

Bu sorunun basit bir cevabı TScrollBox kendisi için DisposeOf çağırmadan önce ebeveyn olarak TScrollBox olan her dinamik olarak oluşturulan denetim için DisposeOf aramak.

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

Burada sınır indeksi erişimi. Tam bir program gösterseydiniz, o zaman size bol bol ders verebileceğimize eminim. Olduğu gibi, bu bir karmaşa. –

+0

Seni yanlış anlayabiliyorum David ama gördüğüm kadarıyla sınır dışı endeks girişi yapılmadı. Sorun, yeni kontroller oluşturmaya başlamadan önce TScrollBox'un gerçekten yok edilmemesiydi. Referans sayısı 0'a ulaşmadı.Bu bellek yetersiz duruma neden olmuş gibi görünüyor. TSCrollBox'ın ebeveyn olarak TScollBox'un sonunda yok edildiği her dinamik olarak yaratılmış kontrol için DisposeOf çağrıldıktan sonra. Bu problemi çözdü. SilverWarior beni doğru yönde itti. – TheAviator

+0

Anladığım şekilde, örnek kodum bu bellek durumundan çıkmadı çünkü orijinal kod kadar fazla bellek kullanmadı. Bu yüzden bu örneği yayınlamak biraz yararsızdı. – TheAviator