使用ARC vs而不使用Delphi释放接口对象

时间:2014-02-14 06:41:28

标签: delphi automatic-ref-counting delphi-xe5

我正在开发一个项目,我有一个像这样的接口TRectangle:

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_ReleaseInterfacedObject中的相同:

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时引用计数为5(引用计数显示在__ObjRelease内)。由于引用计数仍然很高,因此对象不会释放。

我在一个非常简单的演示中重新创建了这个,基本上只使用了我在这里发布的代码。有人可以解释ARC的不同之处是导致引用计数如此之高吗?

1 个答案:

答案 0 :(得分: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的前一个问题中详细讨论了这个问题。