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

然后,他决定使用DataModule并以这种方式实现上述接口(interface):
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的信息,因此不必担心最终尝试。

Windows没有ARC,因此除非有TInterfacedObject之类的实现(这里没有),否则我最终必须使用try..。那是一个错误吗?

该应用程序与ToDo应用程序有关,您可以在其中编写/阅读/保存笔记。数据模块具有FireDAC访问组件,并且使用接口(interface)方法访问数据库。这是为了使UI和db之间保持分隔。

最佳答案

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

09-27 18:19