Newsgroup: it.comp.lang.delphi
Titolo: Interfaccia singleton???

Guardate la unit esemplificativa uGeneric che segue e mettete due bottoni 
su una form, associando al click le due semplicissime procedure sotto 
indicate.
Con la direttiva di compilazione FUNZIA, tutto...funzia. Cioč ho una 
variabile interfaccia singleton (?) di tipo IGeneric che viene 
correttamente distrutta con Unmake.
Togliendo quella direttiva ({$UNDEFINE FUNZIA} o {.$DEFINE FUNZIA}), e 
premendo Button1, prima si vede il messaggio del GetText e subito dopo il 
messaggio del Destroy. Alla pressione successiva di Button1, si ha una AV.
Non capisco perchč.
//......unit di una form vuota....
var
  Form1: TForm1;
implementation
uses
  uGeneric;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(Make.Text)
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  Unmake
end;
////////////////////////////////////////////////////////
unit uGeneric;
interface
{$DEFINE FUNZIA}
type
  IGeneric = interface
    ['{AE3620B2-29F1-46CC-B465-E746D1929BEA}']
    function GetText: string;
    property Text: string read GetText;
  end;
  TGeneric = class(TInterfacedObject, IGeneric)
  protected
    function GetText: string; virtual;
  public
    destructor Destroy; override;
  end;
function Make: IGeneric;
procedure Unmake;
implementation
uses
  Dialogs;
var
{$IFDEF FUNZIA}
  Generic: IGeneric;
{$ELSE}
  Generic: TGeneric;
{$ENDIF}
function Make: IGeneric;
begin
  if not Assigned(Generic) then
    Generic := TGeneric.Create;
  Result := Generic {$IFNDEF FUNZIA} as IGeneric {$ENDIF};
end;
procedure Unmake;
begin
  {$IFNDEF FUNZIA} Generic.Free {$ENDIF};
  Generic := nil;
end;
{ TGeneric }
destructor TGeneric.Destroy;
begin
  ShowMessage(ClassName + '.Destroy');
  inherited;
end;
function TGeneric.GetText: string;
begin
  Result := ClassName + '.GetText';
end;
end.
-- 
Mauro Falzari 
 
 "Se guardi nell'abisso, anche l'abisso guarda in te." 
   (Friedrich Nietzsche)

 messaggio del Destroy. Alla pressione successiva di Button1, si ha una AV.
So per certo che, utilizzando le interfacce, gli oggetti che le 
implementano vengono automaticamente distrutti quando non vi sono più 
riferimenti.
Non ho il tempo di esaminare accuratamente il codice e sono un po' di 
fretta, ma non vorrei che tu fossi incappato nel caso in cui tenti di 
fare la Free di un oggetto che è già stato distrutto da Delphi per via 
di quanto detto precedentemente.
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

 riferimenti.
ma infatti, lo sapevo anch'io che sono reference-counted ed è per questo 
che con la variabile globale privata
  var
    Generic: IGeneric;
la seguente procedura chiama anche il distruttore
  procedure Unmake;
  begin
    Generic := nil;
  end;
Ma allora non capisco perchè definendo la variabile globale privata come
  var
    Generic: TGeneric;
la cosa non funzioni più. Se è globale privata a livello di unit, non 
dovrebbe mai uscire dall'ambito di visibilità, no?
Boh.


per completezza riporto qui la chiara risposta di Marco Cantů:
"La regola č semplice: se usi il reference counting non mischiare
oggetti e interfacce. Se la tua variabile globale č di tipo "oggetto",
la prima volta che un'interfaccia punta all'oggetto il suo refcount va
ad uno, quando la togli torna a zero e l'oggetto viene distrutto, anche
se c'č un reference tradizionale attivo. Se usi una var di tipo
interface, invece, questo aggunge 1 al reference count dell'oggetto e
lo tiene sempre in vita.
L'alternativa č disabilitare il ref count non derivando da
TInterfacedObject ma da altra classe (o implementando direttamente
iInterface)."
