Если реализация для IMyInterface
содержит элемент IAnotherInterface
, а реализация для IAnotherInterface
содержит элемент IMyInterface
, и они ссылаются друг на друга, то их счетчики ссылок никогда не смогут упасть до 0 если вы не очистите одну из ссылок, что, вероятно, означает добавление методов к вашим интерфейсам, например:
type
IAnotherInterface = interface;
IMyInterface = interface
['{guid}']
function GetAnotherInterface: IAnotherInterface;
procedure SetAnotherInterface(Value: IAnotherInterface);
property AnotherInterface: IAnotherInterface read GetAnotherInterface write SetAnotherInterface;
end;
IAnotherInterface = interface
['{guid}']
function GetMyInterface: IMyInterface;
procedure SetMyInterface(Value: IMyInterface);
property MyInterface: IMyInterface read GetMyInterface write SetMyInterface;
end;
.
type
TMyInterface = class(TInterfacedObject, IMyInterface)
private
FAnotherInterface: IAnotherInterface;
public
function GetAnotherInterface: IAnotherInterface;
procedure SetAnotherInterface(Value: IAnotherInterface);
end;
TAnotherInterface = class(TInterfacedObject, IAnotherInterface)
private
FMyInterface: IMyInterface;
public
function GetMyInterface: IMyInterface;
procedure SetMyInterface(Value: IMyInterface);
end;
function TMyInterface.GetAnotherInterface;
begin
Result := FAnotherInterface;
end;
procedure TMyInterface.SetAnotherInterface(Value: IAnotherInterface);
begin
if FAnotherInterface <> Value then
begin
if FAnotherInterface <> nil then FAnotherInterface.SetMyInterface(nil);
FAnotherInterface := Value;
if FAnotherInterface <> nil then FAnotherInterface.SetMyInterface(Self);
end;
end;
function TAnotherInterface.GetMyInterface: IMyInterface;
begin
Result := FMyInterface;
end;
procedure TAnotherInterface.SetMyInterface(Value: IMyInterface);
begin
if FMyInterface <> Value then
begin
if FMyInterface <> nil then FMyInterface.SetAnotherInterface(nil);
FMyInterface := Value;
if FMyInterface <> nil then FMyInterface.SetAnotherInterface(Self);
end;
end;
Теперь смотрите количество ссылок, если вы явно не освобождаете одну из ссылок:
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
...
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 1, I is NOT freed
J := nil; // J.RefCnt becomes 1, J is NOT freed
}
end;
Теперь добавьте явный выпуск к одной из ссылок:
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
...
I.AnotherInterface := nil; // I.RefCnt becomes 1, J.RefCnt becomes 1
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 0, I is freed
J := nil; // J.RefCnt becomes 0, J is freed
}
end;
.
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
J := nil; // I.RefCnt still 2, J.RefCnt becomes 1, J is NOT freed yet
...
I.AnotherInterface := nil; // I.RefCnt becomes 1, J.RefCnt becomes 0, J is freed
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 0, I is freed
}
end;