5

I have a code here:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  IInnerTest = interface (IInterface)
    procedure DoSth;
  end;

  TRekScannerData = record
    Source: Integer;
    Device: IInnerTest;
  end;

  ITest = interface (IInterface)
    procedure DoSth;
  end;

  ATest = class(TInterfacedObject, ITest)
  private
    FInner: Array of TRekScannerData;
  public
    procedure DoSth;
    constructor Create();
    Destructor Destroy();override;
  end;

  AInnerTest = class (TInterfacedObject, IInnerTest)
  private
    FMainInt: ITest;
  public
    constructor Create(MainInt: ITest);
    procedure DoSth;
    Destructor Destroy();override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  test: ITest;

implementation

{$R *.dfm}

{ ATest }

constructor ATest.Create;
begin
  SetLength(FInner, 1);
  FInner[0].Device := AInnerTest.Create(self);
  //<----- Here is the reason. Passing main interface to the inner interface.
end;

destructor ATest.Destroy;
begin
  beep;
  inherited;
end;

procedure ATest.DoSth;
begin
  //
end;

{ AInnerTest }

constructor AInnerTest.Create(MainInt: ITest);
begin
  FMainInt := MainInt;
end;

destructor AInnerTest.Destroy;
begin
  beep;
  inherited;
end;

procedure AInnerTest.DoSth;
begin
  //
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  test := ATest.Create;
  test.DoSth;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  test := nil;
end;

end.

The problem is that Destroy is not called when test is assigned to nil;

I would like to release all the inner interfaces by one statement ... Is it possible? or do I need to prior to nil destroy all inner structures by using another method?

EDIT

The class structure is as follows:

Var x = ITest(ATest class) has ->
  Inner Interface: IInnerTest(AInnerTest class) which has reference to:
    ITest(ATest class)

Nil'ing x doesn't release all structure ...

John
  • 1,834
  • 5
  • 32
  • 60
  • -1 This is what happens when you post fake code. Once you fix all the errors in your fake code, the destructor is indeed called. So, please post real code, code that compiles and runs. And then we can help. – David Heffernan Jan 03 '13 at 12:29
  • Normally, the destructor *is* called when the instance is released. Unfortunately the code you posted doesn't compile and I suspect there's a problem somewhere in the code you omitted from your post. – Ondrej Kelle Jan 03 '13 at 12:29
  • @DavidHeffernan I have uploaded code which can be compiled. it turned out in the meantime that passing main interface to the inner interface is the problem. But how can this be workarounded? – John Jan 03 '13 at 12:56
  • +1 Well done for your edit and so making the question clear – David Heffernan Jan 03 '13 at 13:05

1 Answers1

5

You have a circular reference. Your implementation of IInnerTest holds a reference to ITest. And your implementation of ITest holds a reference to IInnerTest. And this circular reference means that the interface reference count can never go to zero.

The normal solution to this issue to to use a weak reference. Some useful links:

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490