我在理解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._IntfCopy
和System._IntfClear
。
调查System._IntfClear
表明,当_Release
为零时,Source
不会被调用,intf := nil
也是如此。所以毫无疑问为什么对象永远不会被破坏。
但是如何正确使用ARC?
A blog建议不要触摸界面,而只使用非引用计数版本。我知道如何覆盖_AddRef
和_Release
来绕过/禁用ARC,但我想使用ARC,除非有充分的理由不使用它。
(使用Delphi 6)
答案 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的对象生命周期管理方法和接口引用计数,但正确实现这一点非常棘手"