如何通过 reference/pointer 释放和 nil 一个未知的对象实例?
How to free and nil an unknown object instance by reference/pointer?
我有一个包含单个控件的容器。此控件可以是少数类型之一(TMyFrame
后代)。正在 运行 时间创建和销毁控件。
在某些时候我需要释放和 nil 这个控件:
var
C: TControl;
C := SomeForm.MyContainer.Controls[0];
C.Free;
C := nil;
但问题是控件实例本身没有设置为nil
这可能吗?
我想关键是一个实例可以有很多对它的引用。我刚刚意识到一个参考不能 "see" 所有其他未知参考。
对象实例不能为空,在这种情况下不需要任何引用设置为 nil
。
如果 Container.Controls[0]
有效,则 Container
是控件的父级。当您释放该控件时,VCL 会负责从父项中提取已消失的子项,因此在您释放 Container.Controls[0]
后,ControlCount
将变为 0
,而 Container.Controls[0]
将无效.
更新
根据您的评论,您在动态创建控件时并未存储对控件的引用。在这种情况下,您无需将任何内容设置为 nil
.
VCL 框架本身包含对控件的各种引用。但是这些是由框架管理的。你提到
ActiveControl
。如果您销毁活动控件,则框架会负责管理 ActiveControl
属性。
除了销毁控件之外,您不需要做任何事情。 您不需要清除引用,因为您没有引用。
有一种机制可以自动设置对 nil
的引用。它在 TComponent
中实现。在 TComponent
的析构函数中有一个对 SetReference(False)
的调用,它是这样实现的:
procedure TComponent.SetReference(Enable: Boolean);
var
Field: ^TComponent;
begin
if (FOwner <> nil) then
begin
Field := FOwner.FieldAddress(FName);
if Field <> nil then
if Enable then Field^ := Self else Field^ := nil;
end;
end;
所以,假设您有这样的表单:
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button2Click(Sender: TObject);
end;
其中两个按钮是由表单流框架创建的。假设在 Button2Click
中你写 Button1.Free
。然后调用 SetReference
会将 Button1
变量设置为 nil
.
现在,您正在谈论在运行时创建的控件。您没有向我们展示如何定义未设置为 nil
的引用。如果你想安排引用自动设置为 nil
你需要执行以下操作:
- 将引用声明为控件
Owner
的已发布字段。
- 确保控件的
Name
与您在步骤 1 中声明的已发布字段相同。
如果不能这样做,则需要手动编写代码以将引用设置为 nil
。这样做:
SomeReference := nil;
现在,我不知道你将如何获得SomeReference
。只有你自己知道。因为只有您知道要设置为 nil
的此引用的位置。
或者整个问题可能完全是个误会。也许您没有对动态创建的控件的引用。在这种情况下,使用 Controls[]
或其他一些方法来定位控件,调用 Free
,工作就完成了。
我有一个包含单个控件的容器。此控件可以是少数类型之一(TMyFrame
后代)。正在 运行 时间创建和销毁控件。
在某些时候我需要释放和 nil 这个控件:
var
C: TControl;
C := SomeForm.MyContainer.Controls[0];
C.Free;
C := nil;
但问题是控件实例本身没有设置为nil
这可能吗?
我想关键是一个实例可以有很多对它的引用。我刚刚意识到一个参考不能 "see" 所有其他未知参考。
对象实例不能为空,在这种情况下不需要任何引用设置为 nil
。
如果 Container.Controls[0]
有效,则 Container
是控件的父级。当您释放该控件时,VCL 会负责从父项中提取已消失的子项,因此在您释放 Container.Controls[0]
后,ControlCount
将变为 0
,而 Container.Controls[0]
将无效.
更新
根据您的评论,您在动态创建控件时并未存储对控件的引用。在这种情况下,您无需将任何内容设置为 nil
.
VCL 框架本身包含对控件的各种引用。但是这些是由框架管理的。你提到
ActiveControl
。如果您销毁活动控件,则框架会负责管理 ActiveControl
属性。
除了销毁控件之外,您不需要做任何事情。 您不需要清除引用,因为您没有引用。
有一种机制可以自动设置对 nil
的引用。它在 TComponent
中实现。在 TComponent
的析构函数中有一个对 SetReference(False)
的调用,它是这样实现的:
procedure TComponent.SetReference(Enable: Boolean);
var
Field: ^TComponent;
begin
if (FOwner <> nil) then
begin
Field := FOwner.FieldAddress(FName);
if Field <> nil then
if Enable then Field^ := Self else Field^ := nil;
end;
end;
所以,假设您有这样的表单:
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button2Click(Sender: TObject);
end;
其中两个按钮是由表单流框架创建的。假设在 Button2Click
中你写 Button1.Free
。然后调用 SetReference
会将 Button1
变量设置为 nil
.
现在,您正在谈论在运行时创建的控件。您没有向我们展示如何定义未设置为 nil
的引用。如果你想安排引用自动设置为 nil
你需要执行以下操作:
- 将引用声明为控件
Owner
的已发布字段。 - 确保控件的
Name
与您在步骤 1 中声明的已发布字段相同。
如果不能这样做,则需要手动编写代码以将引用设置为 nil
。这样做:
SomeReference := nil;
现在,我不知道你将如何获得SomeReference
。只有你自己知道。因为只有您知道要设置为 nil
的此引用的位置。
或者整个问题可能完全是个误会。也许您没有对动态创建的控件的引用。在这种情况下,使用 Controls[]
或其他一些方法来定位控件,调用 Free
,工作就完成了。