LaK*_*ven 1 arrays delphi interface delphi-xe2 automatic-ref-counting
为了提供尽可能多的信息,这里是我正在做的事情的一个非常基本的例子
type
IMyInterface = interface
[THE_GUID_HERE]
// some methods
end;
TMyInterfaceArray = Array of IMyInterface;
TMyInterfacedObject = class(TInterfacedObject, IMyInterface)
// implementation of the Interface etc. here
end;
TContainingObject = class
private
FIObjectArray: TMyInterfaceArray;
public
constructor Create;
destructor Destroy; override;
procedure NewInstanceOfInterfacedObject;
end;
implementation
constructor TContainingObject.Create;
begin
inherited;
// Just to illustrate that an Instance is being created...
NewInstanceOfInterfacedObject;
end;
destructor TContainingObject.Destroy;
var
I: Integer;
begin
for I := Low(FIObjectArray) to High(FIObjectArray) do
FIObjectArray[I] := nil;
SetLength(FIObjectArray, 0); // Array collapsed
inherited;
end;
procedure TContainingObject.NewInstanceOfInterfacedObject;
var
LIndex: Integer;
begin
LIndex := Length(FIObjectArray);
SetLength(FIObjectArray, LIndex + 1);
FIObjectArray[LIndex] := TMyInterfacedObject.Create;
end;
Run Code Online (Sandbox Code Playgroud)
好的,所以TContainingObject创建了一个实例,然后创建一个TMyInterfacedObject存储在Array of中的实例IMyInterface.
当TContainingObject的destructor被调用,它零的参考和崩溃的阵列.
我的问题是,与任何地方的任何其他引用,TMyInterfacedObject的destructor永远不会被调用,因此内存泄漏.
我做错了什么,或者Delphi的引用计数系统无法应对接口类型数组中接口对象的简单概念?
谢谢你的建议!
更多信息
TContainingObject提供一个Array属性来访问Array中IMyInterface包含的各个实例.
在我的实际代码中,多个接口类型之间存在循环引用.我们建议IMyInterface包含一个函数GetSomething: IAnotherInterface,并IAnotherInterface包含GetMyInterface: IMyInterface(循环引用).这会导致我的问题吗?如果是这样,那么绝对需要循环引用,那么解决方案的目的是什么呢?
如果实现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;
Run Code Online (Sandbox Code Playgroud)
.
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;
Run Code Online (Sandbox Code Playgroud)
现在,当您没有明确地释放其中一个引用时,请查看引用计数:
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;
Run Code Online (Sandbox Code Playgroud)
现在为其中一个引用添加一个显式版本:
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;
Run Code Online (Sandbox Code Playgroud)
.
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;
Run Code Online (Sandbox Code Playgroud)