Delphi interface not reference counted
Asked Answered
I

1

10

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.

Indicative answered 13/8, 2017 at 19:47 Comment(2)
It will. What else to say, it's a horrible weather in Madrid :)Ebberta
@Ebberta same here sadly ;)Indicative
A
17

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.

Atherton answered 13/8, 2017 at 20:0 Comment(4)
So adding the TInterfacedObject would be a mistake or just something extra?Indicative
Where would you put TInterfacedObject? You can only inherit from one class, and that is TDataModule here.Atherton
Ok thank you :) so the data module is already giving me what I need to be sure that It will be ref countedIndicative
It will not be ref counted on non-ARC compiler. TComponent disables reference counting. It has different behavior than TInterfacedObject.Atherton

© 2022 - 2024 — McMap. All rights reserved.