在阅读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之间保持分隔。
最佳答案
TDataModule
是TComponent
的后代,并且TComponent
实现IInterface
和相关的引用计数方法
TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)
但是,
TComponent
禁用了引用计数,并且可以手动或通过非ARC编译器上的所有权模型来管理组件。更精确地说,
TComponent
禁用了引用计数,除非它充当Windows COM对象的包装。这里不是这种情况。在ARC编译器上,手动管理(实际上是自动管理)稍微复杂一些,因为如果不允许通过所有权管理
TComponent
后代,则必须使用DisposeOf
释放它们。TComponent
行为与TInterfacedObject
行为在经典编译器上的引用计数方面有所不同。在上述情况下,没有泄漏,因为
Application
拥有该数据模块,并且它将在所有编译器上适本地管理数据模块的生存期。try... finally
块不是用于内存管理的,而是用于保护BeginUpdate... EndUpdate
的。您必须在所有编译器上保留try...finally
。