Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi interface not reference counted

Reading the Expert Delphi book I have found something that I cannot understand. The author has created an unit with this code:

 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;

Then he decided to use a DataModule and implement the above interface in this way:

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;

So far so good but note that he didn't put TInterfacedObject so here we haven't methods like AddRef and so on. My guess is that the above code is fine but it has to be included inside the try ... finally block.

In the main form (the data module unit is the uses clauses of course) there is a function like this:

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

The code above allows to write code like this:

begin
  GetToDoData.ToDoList(FToDos);

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

Doesn't this produce a memory leak? At least on windows. I am new to delphi so I might fail but I have read online that Android and IOs has ARC so no need to worry about try finally.

Windows does NOT have ARC so I have to use the try .. finally unless there is an implementation like TInterfacedObject (here there isn't). So is that a mistake?


The app is about a ToDo app in which you write/read/save your notes. The data module has FireDAC access components and the interface methods are used to access the db. This is to keep a separation between UI and db stuff.

like image 873
Emma Rossignoli Avatar asked Aug 13 '17 19:08

Emma Rossignoli


Video Answer


1 Answers

TDataModule is TComponent descendant, and TComponent implements IInterface and related reference counting methods

  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)

However, TComponent has reference counting disabled and components are managed either manually or through ownership model on non-ARC compiler.

To be more precise, TComponent has disabled reference counting unless it serves as wrapper for Windows COM object. Which is not the case here.

On ARC compiler there is slight complication with manual management - actually automatic management, because if you don't allow TComponent descendants to be managed through ownership, they have to be released with DisposeOf.

TComponent behavior is different than TInterfacedObject behavior regarding reference counting on classic compiler.

In above case, there is no leak because Application owns that data module and it will manage data module lifetime appropriately on all compilers.


try... finally block is there not for memory management, but to protect BeginUpdate... EndUpdate You have to leave try...finally on all compilers.

like image 157
Dalija Prasnikar Avatar answered Sep 21 '22 11:09

Dalija Prasnikar