如何正确使用ARC接口?

时间:2014-06-15 21:07:18

标签: delphi interface automatic-ref-counting

我在理解ARC与接口的确切工作方式时遇到了问题。在大多数教程中,我已经读过,当ARC计数器达到零时,将接口设置为nil将调用_Release,它将调用Destroy。我已经阅读了一些教程,但目前尚不清楚。

type
  IXXX = interface(IInterface)
  end;

  TXXX = class(TInterfacedPersistent, IXXX)
  public
    constructor Create;
    destructor Destroy; override;
  end;


procedure TForm1.Button4Click(Sender: TObject);
var
  intf: IXXX;
begin
  intf := TXXX.Create; // IntfCopy  will be called. Message "create"
  intf := nil;         // IntfClear will be called. No message "destroy"
end;

{ TXXX }

constructor TXXX.Create;
begin
  inherited;

  showmessage('create');
end;

destructor TXXX.Destroy;
begin
  showmessage('destroy');

  inherited;
end;

当我运行这个程序时,我会收到一条消息"创建",但没有消息" destroy"。我查看了汇编代码,发现调用了System._IntfCopySystem._IntfClear

调查System._IntfClear表明,当_Release为零时,Source不会被调用,intf := nil也是如此。所以毫无疑问为什么对象永远不会被破坏。

但是如何正确使用ARC?

A blog建议不要触摸界面,而只使用非引用计数版本。我知道如何覆盖_AddRef_Release来绕过/禁用ARC,但我想使用ARC,除非有充分的理由不使用它。

(使用Delphi 6)

3 个答案:

答案 0 :(得分:3)

您派生的课程,TInterfacedPersistent在其documentation中有这样的说法:

  与所有持久对象一样,TInterfacedPersistent支持从流中读取和写入其属性的功能。此外,它还提供了IInterface方法的默认实现(_AddRef,_Release和QueryInterface)。这个默认实现只是将这些调用传递给持久对象的Owner的接口,如果有的话。

当引用计数降至零时,当然会调用_Release。但是没有任何事情发生,因为你的对象没有所有者

如果您希望使用引用计数来管理生命周期,那么您应该改为TInterfacedObject。或者提供_AddRef_Release的实现,这些实现计数引用并在引用计数降为零时销毁对象。使用TInterfacedObject作为如何实现该模板的模板。

对于它的价值,你链接到的文章包含了非常糟糕的建议。不要留意它。如果要使用接口,请让引用计数管理生命周期,并仅通过接口引用对象。

答案 1 :(得分:0)

我认为你可能想要使用TInterfacedObject,而是编写TInterfacedPersistent,而不是自动管理引用计数。

通常当我释放一个接口对象时,我总是先断言一行,以确保该对象实际上是一个接口对象。

procedure TForm1.Button4Click(Sender: TObject);
var
  intf: IXXX;
begin
  // create an interfaced object
  intf := TXXX.Create;

  // free an interfaced object
  if Assigned(intf) then
  begin
    assert(intf.InheritsFrom(TInterfacedObject));
    intf := nil;
  end;
end;

请注意,TSingletonImplementation是另一个不自动管理引用计数的类。

答案 2 :(得分:0)

关于您发布的博客链接,对于某些条件,这是合理的,尤其是当某个组件或控件由另一个组件拥有时。

所以你说如果有充分的理由不使用它。有一个:

"如果您的对象是另一个组件所拥有的组件或控件,则它是基于TComponent的不同内存管理系统的一部分。虽然有些类混合了TComponent的对象生命周期管理方法和接口引用计数,但正确实现这一点非常棘手"

Not Using Reference Counting, the offical document said