2016-04-14 12 views
3

Ich habe ein Problem mit NSObject-Instanzen freizugeben, wenn ich nicht erwarte. Ich habe eine Formularvariable vom Typ NSNumber, in Button1 erstelle ich eine Instanz und setze einen Wert, in Button2 lese ich den Wert. Wenn ich nicht in Taste 1 zurückhalte, dann wird die Variable freigegeben und die App hängt, wenn ich auf Button2 klicke, fügt einen Call hinzu, um zu behalten, dass alles funktioniert.Delphi XE6 ARC auf OSX release Variablen

Dies ist auf OSX mit Delphi XE6 mit Firefemonkey.

Hier einige Code

eine Form Variable vom Typ definieren NSNumber

Fv : NSNumber; 

Jetzt ein paar

Schaltflächen hinzufügen

für Button1Click

begin 
    Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0)); 
    ShowMessage(IntToStr(Fv.retainCount)); // value is 1 
    Fv.retain; // comment out this to make it crash on button2 click 
    ShowMessage(IntToStr(Fv.retainCount)); // value is 2, or 1 without the retain 
end; 

für Button2click

Nun scheint am Ende von Button1 Klick zu sein, delphi gibt Fv frei, indem es die Referenzzählung dekrementiert - d. H. Es verhält sich so, als ob es den Gültigkeitsbereich verlässt. Um Fv herumhängen zu lassen, muss ich Fv.retain hinzufügen. Wenn ich auf Button2 ohne den Retain klicke, stürzt es ab.

Sollte ich einbehalten - ich dachte nicht, dass es notwendig war, oder verpasse ich etwas anderes?

tia

+1

Das Gleiche passiert beim Targeting von iOS. Wenn ich Objective-C-Objekte umschließe, muss ich manchmal zurückrufen, manchmal nicht. Ich habe nicht herausgefunden, was der Unterschied ist - aber es ist leicht zu erkennen, wann er benötigt wird :-) – Hans

+0

Ich wusste nicht, dass der OS X-Compiler von XE 6 ARC implementiert hat. Ich dachte nur iOS und Android? –

+2

FWIW, 'numberWithFloat()' erzeugt wahrscheinlich eine Autorelease-Variable (die meisten "Convenience-Konstruktoren" tun dies). Diese müssen in der Tat beibehalten werden, um sie länger zu halten, als bis zum nächsten Autorelease-Zyklus. –

Antwort

2

Dank @RudyVelthius und @RemyLebeau für mich auf dem richtigen Weg setzen.

Das Problem ist kein Delphi-Problem, sondern ein objektives C-Problem (zumindest mein Verständnis von Ziel C ist das Problem).

TNSNumber.OCClass.numberWithFloat(4.0) 

ist ein Convenience-Konstruktor - das seine zu der Autofreigabepool, bedeutet, und das nächste Mal die Hauptlaufschleife ausführt befreit.

Also meine Delphi-Schnittstelle ist in Ordnung, aber leider zeigt es auf etwas, das nicht mehr da ist. Um eine Autorelease-Variable um Call-Call zu behalten. Nur um dies zu beweisen ist das Problem das Aufrufen von alloc/init sollte es beheben. so

Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0)); 

mit

Fv := TNSNumber.Wrap(TNSNumber.Alloc.initWithDouble(4.0)); 

ersetzen und entfernen Sie die behalten und alles funktioniert.

von hier https://stackoverflow.com/a/801000/416047 die Regel ist

Wenn der Wähler ein Objekt zurückkehr das Wort „neu“, „alloc“, „behalten“ oder „Kopie“ in ihm, dann besitzen Sie das zurückgegebene Objekt und sind verantwortlich für die Freigabe, wenn Sie fertig sind.

Sonst besitzen Sie es nicht und sollten es nicht freigeben.Wenn Sie möchten, dass einen Verweis auf ein nicht-eigenes Objekt behält, sollten Sie - [NSObject behalten] für diese Instanz aufrufen. Sie besitzen nun diese Instanz und müssen daher - [NSObject release] für die Instanz aufrufen, wenn Sie damit fertig sind . Sie besitzen also nicht die Instanz, die von - [NSNumber numberWithInt:] zurückgegeben wird und sollten nicht aufrufen, wenn Sie fertig sind. Wenn Sie die zurückgegebene Instanz über den aktuellen Gültigkeitsbereich (wirklich über die Lebensdauer der aktuellen Instanz von NSAutoreleasePool hinausgehend) hinaus behalten möchten, sollten Sie sie beibehalten.