Delphi 接口未被引用计数

Delphi interface not reference counted

阅读专家 Delphi 书我发现了一些我无法理解的东西。作者用这个代码创建了一个单元:

 IToDoData = interface //CRUD
    function ToDoCreate(aValue: TToDo): integer;
    function ToDoRead(id: integer; out aValue: TToDo): boolean;
    function ToDoUpdate(aValue: TToDo): boolean;
    function ToDoDelete(id: integer): boolean;
    procedure ToDoList(aList: TToDos);
  end;

然后他决定用一个DataModule,实现上面的接口是这样的:

type
  TDMToDo = class(TDataModule, IToDoData)
    // ... other code ...
  public
    // IToDoData
    function ToDoCreate(aValue: TToDo): integer;
    function ToDoRead(id: integer; out aValue: TToDo): boolean;
    function ToDoUpdate(aValue: TToDo): boolean;
    function ToDoDelete(id: integer): boolean;
    procedure ToDoList(aList: TToDos);
  end;

到目前为止一切顺利,但请注意,他没有 放置TInterfacedObject,所以这里我们没有 AddRef 等方法。我的猜测是上面的代码没问题,但它必须包含在 try ... finally 块中。

在主窗体中(数据模块单元当然是uses子句)有这样一个函数:

function TFormToDo.GetToDoData: IToDoData;
begin
  if DMToDo = nil then
    DMToDo := TDMToDo.Create(Application);
  Result := DMToDo;
end;

上面的代码允许这样写:

begin
  GetToDoData.ToDoList(FToDos);

  ListView1.BeginUpdate;
  try
    //populate the list
  finally
    ListView1.EndUpdate;
  end;
end;

这不会产生内存泄漏吗?至少 windows。我是 delphi 的新手,所以我可能会失败,但我在网上看到 Android 和 IOs 有 ARC,所以无需担心 try finally。

Windows 没有 ARC 所以我必须使用 try .. finally 除非有像 TInterfacedObject 这样的实现(这里没有)。那么这是一个错误吗?


该应用程序是关于一个 ToDo 应用程序,您可以在其中 write/read/save 您的笔记。数据模块具有 FireDAC 访问组件,接口方法用于访问数据库。这是为了在 UI 和数据库之间保持分离。

TDataModuleTComponent 后代,并且 TComponent 实现了 IInterface 和相关的引用计数方法

  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)

但是,TComponent 禁用了引用计数,并且在非 ARC 编译器上手动或通过所有权模型管理组件。

更准确地说,TComponent 已禁用引用计数,除非它用作 Windows COM 对象的包装器。这不是这里的情况。

在 ARC 编译器上,手动管理稍微有些复杂 - 实际上是自动管理,因为如果您不允许 TComponent 后代通过所有权进行管理,则必须使用 DisposeOf 释放它们.

TComponent 行为不同于 TInterfacedObject 关于经典编译器引用计数的行为。

在上述情况下,没有泄漏,因为 Application 拥有该数据模块,并且它将在所有编译器上适当地管理数据模块生命周期。


try... finally 块不是用于内存管理,而是用于保护 BeginUpdate... EndUpdate 您必须在所有编译器上保留 try...finally