Интерфейсы в Delphi появились, когда понадобилось поддержать работу с COM и они не очень стройно вписались в язык. В итоге смешивать работу с классами и интерфейсами следует крайне осторожно, всему виной счетчик ссылок, значение которого в классах изначально равно нулю.

В качестве примера форма с одной кнопкой.

unit Unit1;

interface

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

type
  TMyClass = class(TInterfacedObject)
  public
    destructor Destroy; override;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Kill(Intf: IInterface);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMyClass }

destructor TMyClass.Destroy;
begin
  ShowMessage('TMyClass.Destroy');
  inherited;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyClass: TMyClass;
begin
  MyClass := TMyClass.Create;
  try
    Kill(MyClass);
  finally
    MyClass.Free;
  end;
end;

{$O-} // выключим оптимизатор, чтобы он не выбросил обращение к Intf
procedure TForm1.Kill(Intf: IInterface);
begin
  // Используем интерфейс
  // ...
  ShowMessage('TMyClass.Kill');
end;
{$O+}

end.

При нажатии на кнопку появляются сообщения:

  1. TMyClass.Kill
  2. TMyClass.Destroy
  3. TMyClass.Destroy
  4. Access violation at address 00403BD2 in module ‘Project1.exe’. Read of address FFFFFFF8.

Почему такое происходит?

Разберем ход выполнения процедуры Kill:

// Изначально Intf.RefCount = 0, это нормальное состояние для TInterfacedObject
// Выполняется Intf._AddRef, теперь RefCount = 1 
procedure TForm1.Kill(Intf: IInterface);
begin
  ShowMessage('TMyClass.Kill');

  // Интерфейс выходит из области видимости, выполняется Intf._Release
  // И, так как RefCount стал равень нулю, объект уничтожается: TMyClass.Destroy
  // Это и становится причиной того, что дальше все идет наперекосяк.
end;

Способ обойти такую проблему есть — переопределить методы _AddRef и _Release таким образом, чтобы обнуление счетчика ссылок не вызывало освобождение объекта. Но такой шаг увеличивает сложность, т.к. в коде, где часть интерфейсов использует счетчик ссылок, а часть нет, легко запутаться. Тем не менее, в VCL переопределение счетчика ссылок используется. У наследников TComponent счетчик ссылок то есть, то его нет :)

function TComponent._AddRef: Integer;
begin
  if FVCLComObject = nil then
    Result := -1   // -1 indicates no reference counting is taking place
  else
    Result := IVCLComObject(FVCLComObject)._AddRef;
end;

function TComponent._Release: Integer;
begin
  if FVCLComObject = nil then
    Result := -1   // -1 indicates no reference counting is taking place
  else
    Result := IVCLComObject(FVCLComObject)._Release;
end;

Врядли в языке без сборщика мусора можно было бы реализовать интерфейсы более удобно. Разве что принудить программиста явно вызывать _AddRef и _Release.

Update
Аналогичная проблема и попытка избежать уничтожения объекта при использовании функции Supports:
http://delphisorcery.blogspot.com/2011/10/supports-killing-objects.html

Update 2
Расширенная версия статьи на Хабре.