use*_*960 4 delphi interface custom-controls
我已经读过,如果一个类实现了一个接口,它现在被引用计数,不应该通过调用来管理它的内存free.
但是,如果您创建自定义控件并使其实现接口,那么如何防止其owner管理内存?例如,当您在设计时将其放在表单上时,引用计数和所有者内存管理会对抗吗?
谢谢你的时间.
控件是从这种行为除外,因为它们不从中继承TInterfacedObject.
因此,它们不进行引用计数,它们的引用计数被设计为-1 ).
所有控件的继承TComponent都是这样的:
TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
*)需要注意的是,如果分配了VCLComObject,它们将遵循Object的引用计数(通常不会停留在-1).
VCLComObject大多数组件都是零.
它仅用于IDE生成的组件包装器来包装COM对象.
看到:TComponent.ComObject
因此,您可以为心脏内容添加界面.只要你记得在完成后释放组件,它就没有任何问题.
您可以通过测试来测试控件是否引用计数:
DoesNotRefCount:= Supports(MyObject, IInterfaceComponentReference)
and (TComponent(MyObject).VCLComObject = nil);
Run Code Online (Sandbox Code Playgroud)
不要调用_AddRef您的对象来测试它是否返回-1,因为这可能会破坏使用ref计数的对象.
如果您的引用计数对象从0开始,然后您执行a _AddRef后跟a,_Release您将销毁该对象,即使Delphi正要_AddRef进一步调用两条指令.
如果您想创建自己的不进行引用计数的对象,那么添加标记接口也是一个好主意:
INoRefCounting = interface
['{CAD60ADF-C49A-46FB-BB5A-CC54BD22C7EB}']
end;
Run Code Online (Sandbox Code Playgroud)
在较新的Delphi中,你可以从TSingletonImplementation哪个下降虚拟无引脚计数.
在较旧的Delphi中从TObject(或TWhatever)下降并实现无引用计数如下:
function TMyObject.QueryInterface(const IID: TGUID; out Obj): HResult; {stdcall;}
begin
if GetInterface(IID, Obj) then Result := S_OK
else Result := E_NOINTERFACE;
end;
function TMyObject._AddRef: Integer; {stdcall;}
begin
Result := -1;
end;
function TMyObject._Release: Integer; {stdcall;}
begin
Result := -1;
end;
Run Code Online (Sandbox Code Playgroud)
最后的注释
如果你想100%确定你的自定义控件没有引用计数,你必须覆盖_AddRef/ _Release方法来删除基于的条件引用计数VCLComObject.
警告
如果控件的生命周期很短,并且您仍然持有对这些控件的接口的引用更长时间,那么您将遇到问题.
如果您遇到这种情况,可能需要将调试代码添加到_AddRef,_Release以及Destroy跟踪引用计数的方法,并在重新计数达到零到迟到或过早时发出信号.