Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   iOS Forms & ARC "spielereien" (https://www.delphipraxis.net/175568-forms-arc-spielereien.html)

Mavarik 1. Jul 2013 16:33

Forms & ARC "spielereien"
 
Hallo Zusammen!

Was erwartet man von ARC?

App mit 2 Forms... Main & Form1

Beispiel 1

Delphi-Quellcode:
Procedure TMain.Button1Click(Sender: TObject);
Var
  F : TForm1;
begin
  F := TForm1.Create(NIL);
  F.Show
end;
Was erwartet man?
Das Form wird angezeigt und nachdem man "out of Scope" ist, wird das Fenster wieder geschlossen und die
OnDestroy aufgerufen, oder?

Nöö eben nicht. F.RefCount ist 2 daher wird das Fenster weder geschlossen noch die Destroy aufgerufen.

Beispiel 2

Delphi-Quellcode:
Procedure TMain.Button1Click(Sender: TObject);
Var
  F : TForm1;
begin
  F := TForm1.Create(NIL);
  F.Show
  F := NIL;
end;
Bringt logischerweise auch nix.

Noch besser finde ich allerdings folgendes:

Beispiel 3

Delphi-Quellcode:
procedure TMain.Button1Click(Sender: TObject);
var
  [WEAK] F : TForm1;
begin
  F := TForm1.Create(NIL);
  F.Show;
end;
Hierbei ist F.RefCount=1 nachdem "out of scope" sollte jetzt F.RefCount endlich mal 0 sein, oder?

Naja... Auf jeden Fall wird das Fenster dargestellt und funktiniert "ganz prima"

Also wie zum Geier kann ich das Fenster schliessen und den onDestroy aufrufen?

Wie wäre es mit... Moment muss die IDE neu starten (nicht genug Arbeitsspeicher) da war wohl ein Memory Leak!
Weiter geht's...


Delphi-Quellcode:
Procedure TForm1.FormClose(Sender: TObject; var Action : TCloseAAction);
begin
  Action := TCloseAction.caFree; // Let's do the MDI Style
end;
Na endlich die OnDestroy wird aufgerufen... Aber halt...

Debugger Exception-Klasse SIGSEGV(11) ausgelöst. (Zeile 3569 in FMX.Platform.iOS)
> Form.MouseLeave blöde nur das Form jetzt schon NIL ist...

OK Dann anders!

Beispiel 4

Delphi-Quellcode:
procedure TMain.Button1Click(Sender: TObject);
var
  F : TForm1;
begin
  F := TForm1.Create(NIL);
  F.Showmodal;
  F.Free;
end;
Mit einem Button ModalResult := mrOK setzen...

UND? OK Fenster ist weg...

Unnötig zu erwähnen, dass die OnDestroy wieder nicht aufgerufen wird!

Noch jemand ne Idee?


Mavarik

Crocotronic 1. Jul 2013 17:07

AW: Forms & ARC "spielereien"
 
Was hälst du von
Delphi-Quellcode:
 Form2:= TForm2.Create(nil);
 try
  Form2.ShowModal;
 finally
  Form2.Destroy;
  Form2:= nil;
 end;
?

Mavarik 1. Jul 2013 17:18

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Crocotronic (Beitrag 1220306)
Was hälst du von
Delphi-Quellcode:
 Form2:= TForm2.Create(nil);
 try
  Form2.ShowModal;
 finally
  Form2.Destroy;
  Form2:= nil;
 end;
?

OK mal abgesehen davon, dass man Destroy nicht aufrufen soll, funktioniert es mit einem Testprogramm zwar, aber ich musste leider feststellen, dass
ShowModal in IOS nicht funktioniert, da dann einige Sachen nicht animiert werden!

Mavarik

jbg 1. Jul 2013 17:39

AW: Forms & ARC "spielereien"
 
Der "richtige" Weg ist Form.DisposeOf aufzurufen (welches aber nicht in älteren Delphi Versionen vorhanden ist). Die Funktion hat Embarcadero genau für diesen Fall eingebaut, nachdem sie das "Free" zweckentfremdet haben. Aber "DisposeOf sollte man nur in Sonderfällen aufrufen". Leider sind aber die alle (GUI) Controls Sonderfälle, da irgendwo im inneren der FMX eine Strong-Reference auf sie existiert.
So kann man ein Konzept auch ad absurdum führen.

Der schöne Günther 1. Jul 2013 17:47

AW: Forms & ARC "spielereien"
 
Ich kenne mich mit Delphi-Projekten unter iOS nicht aus, aber das Application-Objekt (falls es das unter iOS auch gibt), merkt sich doch alle seine Formen. Bislang doch nur ein Sonderfall bei Formen, oder?

jbg 1. Jul 2013 17:57

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1220315)
Bislang doch nur ein Sonderfall bei Formen, oder?

Kann schon sein. Die FMX wurde ohne ARC (im Kopf) entwickelt und erst nachträglich ARC-kompatibel gefrickelt. Aber eigentlich geht mir die FMX sonstwo vorbei, so schlecht wie die geschrieben ist (und das bezieht sich nicht nur auf die Performance).

Mavarik 1. Jul 2013 19:14

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von jbg (Beitrag 1220314)
Der "richtige" Weg ist Form.DisposeOf aufzurufen...

Jo das gibt an ganz neuen Stellen die Exceptions...

Elfriede 1. Jul 2013 20:23

AW: Forms & ARC "spielereien"
 
Liste der Anhänge anzeigen (Anzahl: 1)
Wir sollte mal schauen, nach welchen Mustern das FMX-Framework sich verhält. Den kompletten Total-Ausfall, den Du da beschreibst, konnte ich so nicht nachvollziehen. Anbei der Lebens-Zyklus eines Child-Forms, das ich über eine Schaltfläche auf dem Haupt-Form aufgerufen habe:

Anhang 39510

Zumindest im Simulator - diese Einschränkung muss ich noch machen. Vielleicht kann ich meinem Mitbewohner nachher wieder sein iPhone klauen, dann kann ich es auch dort versuchen. :stupid:


Elli

arnof 1. Jul 2013 20:42

AW: Forms & ARC "spielereien"
 
Hallo,

wenn Du dir mal den Projektquelltext anschaust, dann machen die die Forms so:


Application.CreateForm(TFormxyz, Formxyz);

Dann wird die Form wahrschein lich beim Destory des Applicationsobject kommen ....

Wenn Du natürlich 100 Forms hast, dann wird dies wahrscheinlich nicht gehen ....

Ich hatte mich mit dem Arc auch einwenig beschäftigt und gesehen, das der RefCount bei manchen Sachen nicht mit 1 erstellt wird sondern mit einer großen Zahl.

Also mal testen formxyz.Refcount ausgeben lassen!

Stevie 2. Jul 2013 08:08

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von arnof (Beitrag 1220337)
Hallo,

wenn Du dir mal den Projektquelltext anschaust, dann machen die die Forms so:


Application.CreateForm(TFormxyz, Formxyz);

Dann wird die Form wahrschein lich beim Destory des Applicationsobject kommen ....

Das stimmt nur für Forms, die man im Projekt als auto-create angegeben hat - Frank erzeugt das Form selber.

Generell wird ARC wohl ein kleines Problemchen mit so fire and forget Aktionen haben. Im ersten Beispiel müsste es schon knallen (bzw das Form sofort wieder geschlossen und freigegeben werden), wenn die lokale Variable die einzige Referenz wäre. Das Form wird angezeigt und danach die Routine verlassen (Show ist nicht blockierend). Das heißt also, irgendwo wird es eine Referenz auf das Form geben. Ich bin der Meinung, Beispiel 3 sollte das sein, was funktionieren sollte - die AV in der FMX.Platform.iOS sollte abgefangen werden (bzw nil safe implementiert werden).

Mavarik 2. Jul 2013 10:29

AW: Forms & ARC "spielereien"
 
Das Problem fängt ja damit an, dass nach einem

F := TForm.Create(NIL)

F.Refcount = 2 ist.

Achso...

Und beim "Klassiker"

F := TForm.Create(Application)

F.Refcount = 4 ist.


Mavarik

Elvis 2. Jul 2013 11:49

AW: Forms & ARC "spielereien"
 
Ich hätte eigentlich erwartet, dass "Show" den RefCount um einen erhöht, da es ja non-blocking ist.
Wenn man es mit Show gezeigt hat, sollte das Schließen den Zähler um 1 verringern.

Zumindest hätte ich das so angenommen. Wie soll das ja auch sonst funktionieren?
Wenn man es modal zeigt, dann sollte da nix passieren.

Wie es tatsächlich passiert? kA
Aber es ist irgendwo nicht schlecht, dass sich EMBT Gedanken macht, um ein bissel Garbage Collection zu erlauben. Denn mit dem alten Modell gab es ja die abstrusesten Konventionen um bloss keine Leaks zu erzeugen.

Mavarik 2. Jul 2013 12:58

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Elvis (Beitrag 1220390)
Ich hätte eigentlich erwartet, dass "Show" den RefCount um einen erhöht, da es ja non-blocking ist.
Wenn man es mit Show gezeigt hat, sollte das Schließen den Zähler um 1 verringern.

Das Problem ist, wie soll man sauber alles free(n), wenn irgendwo versteckte Referenzen sind.

Show ändert (natürlich) nicht den RefCounter...

Das blöde ist, wenn man die Referenzen killt um alles sauber zu machen, greift Firemonkey immer noch an irgend einer Stelle auf das Formular zu
um noch eine Animation ab zu schließen oder was auch immer...

Und dann knallt es..

Mavarik

Daniel 2. Jul 2013 13:08

AW: Forms & ARC "spielereien"
 
Dann trenne Deine Business-Logik vom FMX-Framework. An einem Punkt X, an dem Deine App der Ansicht ist, das Formular könne weg, räumt sie alles, was sie selbst erzeugt hat, auch wieder ab und gibt den Rest an FMX zurück. Mehr kann man letztlich eh nicht tun und was dann übrig bleibt, kann nicht mehr gravierend viel Speicher kosten.

Mavarik 2. Jul 2013 13:42

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Daniel (Beitrag 1220401)
Dann trenne Deine Business-Logik vom FMX-Framework. An einem Punkt X, an dem Deine App der Ansicht ist, das Formular könne weg, räumt sie alles, was sie selbst erzeugt hat, auch wieder ab und gibt den Rest an FMX zurück. Mehr kann man letztlich eh nicht tun und was dann übrig bleibt, kann nicht mehr gravierend viel Speicher kosten.

Tja das ist aber auch nur ein Workaround!

Hab jetzt - auf Olaf's Rat - mal das Form mit Release freigegeben...

Das sieht recht gut aus...

Fenster mit Show anzeigen und danach über einen Fensterhandler wieder schliessen...

Also ein weiteren Test in einer For-Schleife!

so ab dem 25. Form.Show und Close über einen Fensterhandler wird der iPhone Bildschirm zwischen durch schwarz
und der Show kommt immer verzögerter... bei 35 Form Show#s: Exception in System.pas in _DbgExcNotify

Also das war es auch noch nicht...

Mavarik

Sir Rufo 2. Jul 2013 14:00

AW: Forms & ARC "spielereien"
 
Ich denke jetzt einfach mal laut:

Ein iOS Device ist ja nun mal kein MultiWindow-Anzeiger, sondern es wird immer nur eine View angezeigt.

Daraus ergibt sich, dass jede View als Singleton implementiert werden könnte/angesehen werden kann. Die anzuzeigenden Daten übergibt man der View mit einem ViewModel und lässt die View anzeigen.

Die Views müssen dabei nicht direkt alle beim Start erzeugt werden, aber wenn einmal erzeugt, dann immer wieder verwenden.

Einen Controller gebaut der das ViewModel bekommt, darüber die View auswählt und anzeigt.
Damit kann dann auch die nette Zurück-Funktion implementiert werden ;)

Mavarik 2. Jul 2013 14:19

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Sir Rufo (Beitrag 1220414)
Ich denke jetzt einfach mal laut:

Ein iOS Device ist ja nun mal kein MultiWindow-Anzeiger, sondern es wird immer nur eine View angezeigt.

Daraus ergibt sich, dass jede View als Singleton implementiert werden könnte/angesehen werden kann. Die anzuzeigenden Daten übergibt man der View mit einem ViewModel und lässt die View anzeigen.

Die Views müssen dabei nicht direkt alle beim Start erzeugt werden, aber wenn einmal erzeugt, dann immer wieder verwenden.

Einen Controller gebaut der das ViewModel bekommt, darüber die View auswählt und anzeigt.
Damit kann dann auch die nette Zurück-Funktion implementiert werden ;)

OK gebe ich Dir 100%ig Recht!

Frei nach dem Motto... Lass die Form's doch rumgammeln... Der nächste App-Kill Event vom iOS wird es richten... ;-)

Mavarik

arnof 3. Jul 2013 19:55

AW: Forms & ARC "spielereien"
 
Liste der Anhänge anzeigen (Anzahl: 1)
So ich habe es mal getestet und alles geht wie man es gelernt (war mal beim Forumschef in einer Schulung zu iOS ....):

zuerst die zu erzeugende Form:

Code:
type
  TFM_Debug = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  FM_Debug: TFM_Debug;

implementation

uses unit1;

{$R *.fmx}

procedure TFM_Debug.FormCreate(Sender: TObject);
begin
 Label1.Text:=self.Name;
 Form1.Memo1.Lines.Add('Create '+Label1.Text);
end;

procedure TFM_Debug.FormDestroy(Sender: TObject);
begin
 Form1.Memo1.Lines.Add('Destroy '+Label1.Text);
end;
Nun das Hauptfenster mit der Debugausgabe:

Code:
uses Unit2;

var FDebug : array of TFM_Debug;

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
 var i:integer;
begin
 FDebug:=nil;
 SetLength(FDebug,Trunc(SpinBox1.Value));
 for I := 0 to length(FDebug)-1 do begin
  FDebug[i]:=TFM_Debug.Create(self);
 end;
 Button1.Enabled:=False;
 Button2.Enabled:=True;
end;

procedure TForm1.Button2Click(Sender: TObject);
 var i:integer;
begin
 for I := 0 to length(FDebug)-1 do begin
  FDebug[i].Close;
  FDebug[i].Release;
 end;
 Memo1.Lines.Add('alle released now Nil');
 FDebug:=nil;
 Button1.Enabled:=True;
 Button2.Enabled:=False;
end;
Im Screenshot seht man das der Destory erst kommt, wenn ich das Array indem ich die Forms ablegt = nil setzte , vorher nicht, da noch eine Refernz darauf besteht :thumb:

Sir Rufo 3. Jul 2013 20:41

AW: Forms & ARC "spielereien"
 
@arnof

Aber so hast du das bestimmt nicht bei Cheffe gelernt (s.
Delphi-Quellcode:
Form1
) :mrgreen:

arnof 3. Jul 2013 21:36

AW: Forms & ARC "spielereien"
 
Zitat:

Zitat von Sir Rufo (Beitrag 1220667)
@arnof

Aber so hast du das bestimmt nicht bei Cheffe gelernt (s.
Delphi-Quellcode:
Form1
) :mrgreen:

war ja für könner mit viel bla bla zu ARC, den ich erstmal keine große Beachtung Geschenk hatte, aber wie es so ist, dann fliegt einem der Kram um die Ohren .... :pale:

siehe

http://www.delphipraxis.net/174930-i...r-bug-arc.html


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:14 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz