9

阅读 Expert 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;

然后他决定使用a 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;

这不会产生内存泄漏吗?至少在窗户上。我是 delphi 的新手,所以我可能会失败,但我在网上读到 Android 和 IOs 有 ARC,所以不用担心最后尝试。

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


该应用程序是关于一个待办事项应用程序,您可以在其中编写/读取/保存您的笔记。数据模块具有FireDAC访问组件,接口方法用于访问数据库。这是为了保持 UI 和数据库内容之间的分离。

4

1 回答 1

16

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所有编译器。

于 2017-08-13T20:00:09.243 回答