2014-02-14 18 views
3

我工作的一個項目,我有一個接口TRectangle這樣的:解放出來與ARC的接口對象VS無 - 德爾福

IBoardShape = interface(IInterface) 
    function GetColor: integer; 
    procedure SetColor(const aColor: integer); 
    property Color: integer read GetColor write SetColor; 
end; 

TGameRectangle = class(TRectangle, IBoardShape) 
private 
    FColor: integer; 
    procedure SetColor(const aColor: integer); 
    function GetColor: integer; 
    property Color: integer read GetColor write SetColor; 
protected 
    {$IFNDEF AUTOREFCOUNT} 
    [Volatile] FRefCount: Integer; 
    {$ENDIF} 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
end; 

_AddRef_Release是一樣InterfacedObject

function TGameRectangle._AddRef: Integer; 
begin 
{$IFNDEF AUTOREFCOUNT} 
    Result := AtomicIncrement(FRefCount); 
{$ELSE} 
    Result := __ObjAddRef; 
{$ENDIF} 
end; 

function TGameRectangle._Release: Integer; 
begin 
{$IFNDEF AUTOREFCOUNT} 
    Result := AtomicDecrement(FRefCount); 
    if Result = 0 then 
    Destroy; 
{$ELSE} 
    Result := __ObjRelease; 
{$ENDIF} 
end; 

要創建一個矩形我這樣做:

var 
    lRect: TGameRectangle; 
begin 
    lRect := TGameRectangle.Create(self); 
    lRect.Parent := Layout1; 
    lRect.Align := TAlignLayout.alClient; 
    FIntObj := lRect as IBoardShape; 

後來我自由它通過將FIntObj設置爲nil。在Windows上,當我遵循_Release時,引用計數爲1,計數減少並釋放對象。在Android上運行時,當輸入_Release(引用計數顯示在__ObjRelease的內部)時,引用計數爲5。由於引用計數仍然很高,該對象不會釋放。

我在一個非常簡單的演示中使用基本上只是我在這裏發佈的代碼重新創建了這個。有人可以解釋一下ARC的不同之處在於導致引用計數如此之高?

+0

使用ARC **時,每個對該實例的引用都會增加RefCount。您傳遞的是一個所有者和一個父項,並且它們都持有**最少**一個該實例的引用。加上你的界面引用你至少有3個 - 但肯定有更多的引用是由所有者和父引起的。 –

+2

@SirRufo ...除非您使用[[weak]]參考,這是必需的,例如爲循環引用。參見[Marco的文章](http://blog.marcocantu.com/blog/automatic_reference_counting_for_delphi.html)。恕我直言,德爾福內存模型的這種重大變化是有史以來最糟糕的想法之一。 –

+0

@ArnaudBouchez德爾福太害怕改變,特別是突破變化。我渴望臺式機編譯器ARC的出現。使用'[weak]'屬性沒有任何問題。 –

回答

1

所有這些在ARC中都是不必要的,因爲ARC已經計算了引用並控制了生命週期。

在ARC下,您可以也應該依賴基類的IInterface實現。

在ARC你的代碼應該是這樣的:

TGameRectangle = class(TRectangle, IBoardShape) 
private 
    FColor: integer; 
    procedure SetColor(const aColor: integer); 
    function GetColor: integer; 
    property Color: integer read GetColor write SetColor; 
end; 

你更大的問題是,你的代碼不能在非ARC平臺上工作。這是因爲你擁有一個TComponent後代。因此,所有者持有對矩形對象的引用,並在其被銷燬時嘗試銷燬。除此之外,您的界面引用計數還會承擔所有權。通常,對象需要擁有一個所有者。你的設計給了他們兩個。

如果對象沒有所有者,您應該在非ARC平臺上僅通過接口引用計數來管理生命週期。我在你的上一個問題的answer中對此進行了更詳細的討論。

+0

不會僅僅爲'TRectangle'的構造函數傳遞'nil'作爲'AOwner'解決這個問題? –

+0

@Günther美麗的確會。但他沒有。 –

+0

感謝您的幫助,在這個答案和另一個。我嘗試傳遞nil,但是一旦創建對象的方法退出(在System中的_IntfCopy內),我就會得到一個異常。我不認爲我會試圖做到這一點(就像你說的感覺就像使用我自己的設計違背設計一樣),我會跟蹤對象。 – Sentient