Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent destruction of object passed by interface

i don't have much experience with interfaces in Delphi and Delphi at all.

Example:

IListModel = interface
    function At(row, col : Integer) : String;
end;

MyModel = class(TInterfacedObject, IListModel)
public
    function At(row, col : Integer) : String;
    procedure ManipulateA;
    procedure ManipulateBogus;
end;

There is a view that can visualize objects that implement the IListModel interface.

View = class(TForm)
public
    constructor Create(model : IListModel); reintroduce;
end;

My app holds a MyModel instance

MyApp = class({...})
strict private
    model : MyModel;
public
 // ...
end;

In the app i create the model and work with it.

procedure MyApp.LoadModel;
procedure MyApp.OnFoo;
begin
    model.ManipulateBogus;
end;

Now, i want to show the data

procedure MyApp.ShowModel;
var
    v : View;
begin
    v := View.Create(model); // implicit to IListView > refCount=1
    v.ShowModal;
    FreeAndNil(v);
    // refCount = 0
    // oops, my model is dead now
end;

I'm wondering what's the best way to solve this problem. In MyApp i could hold both, the instance model : MyModel AND via IListModel interface. Or I could introduce a new interface IMyModel and hold the model by this interface in the MyApp class. I had to use if Supports(...) in the ShowModel method to get the IListModel interface. Or i derive the MyModel class from another non refcounting base class (TInterfacedPersistent or a self written class). Any other ideas?

What is the best way to work with interfaces in such situations?

Edit: A non ref counting base class:

function NonRefCountingObject.QueryInterface(const IID: TGUID;
                                             out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := S_OK
  else
    Result := E_NOINTERFACE;
end;

function NonRefCountingObject._AddRef: Integer;
begin
    Result := -1;  // no reference counting
end;

function NonRefCountingObject._Release: Integer;
begin
    Result := -1;  // no reference counting
end;

Is this implementation ok?

like image 264
hansmaad Avatar asked Feb 26 '23 20:02

hansmaad


1 Answers

If you want to use the reference counting that comes with interfaces, you should only reference that object through interfaces. No references to the object other than through interfaces and do not free the object yourself.

Or you could disable the reference counting by overriding _AddRef and _Release and destroy the object like you are used to. This is what TComponent does.

Or keep the reference counting, but call AddRef and Release when you reference it like an object.

edit

using a const parameter prevents reference count updating and speeds up your code:

constructor Create(const model : IListModel); reintroduce;
like image 112
Lars Truijens Avatar answered Mar 08 '23 10:03

Lars Truijens