Delphi 从 Android 的表单中删除 FireMonkey 元素
Delphi delete FireMonkey element from Form on Android
我在 OnShow
事件中使用以下代码在我的表单上创建了一个元素:
procedure TForm4.FormShow(Sender: TObject);
var
VertScrollLink:TVertScrollBox;
begin
VertScrollLink := TVertScrollBox.Create(form4);
VertScrollLink.Align := TAlignLayout.Client;
VertScrollLink.Parent := form4;
end;
在某些操作中,我需要动态删除布局:
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if (form4.Components[LIndex].ToString='TVertScrollBox') then
begin
//showmessage(form4.Components[LIndex].ToString);
form4.Components[LIndex].Free;
end;
end;
此代码在 Windows 上运行良好,但不会在 Android 上删除任何内容。
原因是因为 Delphi uses Automatic Reference Counting for Objects 在移动平台上(iOS 和 Android),而不是在桌面平台上(Windows 和 OSX)。你的 Free()
实际上是一个空操作,因为从 Components[]
属性 访问组件会增加它的引用计数,然后 Free()
会减少它(事实上,编译器应该发出有关代码无效的警告)。该组件仍然有对它的活动引用(它的 Owner
和 Parent
),所以它实际上并没有被释放。
如果要强制释放组件,需要对其调用DisposeOf()
,eg:
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if form4.Components[LIndex] is TVertScrollBox then
begin
form4.Components[LIndex].DisposeOf;
end;
end;
或者,删除活动引用并让 ARC 正常处理销毁:
var
VertScrollLink: TVertScrollBox;
LIndex: Integer;
begin
...
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if form4.Components[LIndex] is TVertScrollBox then
begin
VertScrollLink := TVertScrollBox(form4.Components[LIndex]);
VertScrollLink.Parent := nil;
VertScrollLink.Owner.RemoveComponent(VertScrollLink);
VertScrollLink := nil;
end;
end;
...
end;
也就是说,您可以考虑跟踪您创建的组件,这样您以后就不需要使用循环来查找它了:
type
TForm4 = class(TForm)
procedure FormShow(Sender: TObject);
...
private
VertScrollLink: TVertScrollBox;
...
end;
procedure TForm4.FormShow(Sender: TObject);
begin
VertScrollLink := TVertScrollBox.Create(Self);
VertScrollLink.Align := TAlignLayout.Client;
VertScrollLink.Parent := Self;
end;
begin
...
if Assigned(VertScrollLink) then
begin
VertScrollLink.DisposeOf;
{ or:
VertScrollLink.Parent := nil;
VertScrollLink.Owner.RemoveComponent(VertScrollLink);
}
VertScrollLink := nil;
end;
...
end;
我在 OnShow
事件中使用以下代码在我的表单上创建了一个元素:
procedure TForm4.FormShow(Sender: TObject);
var
VertScrollLink:TVertScrollBox;
begin
VertScrollLink := TVertScrollBox.Create(form4);
VertScrollLink.Align := TAlignLayout.Client;
VertScrollLink.Parent := form4;
end;
在某些操作中,我需要动态删除布局:
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if (form4.Components[LIndex].ToString='TVertScrollBox') then
begin
//showmessage(form4.Components[LIndex].ToString);
form4.Components[LIndex].Free;
end;
end;
此代码在 Windows 上运行良好,但不会在 Android 上删除任何内容。
原因是因为 Delphi uses Automatic Reference Counting for Objects 在移动平台上(iOS 和 Android),而不是在桌面平台上(Windows 和 OSX)。你的 Free()
实际上是一个空操作,因为从 Components[]
属性 访问组件会增加它的引用计数,然后 Free()
会减少它(事实上,编译器应该发出有关代码无效的警告)。该组件仍然有对它的活动引用(它的 Owner
和 Parent
),所以它实际上并没有被释放。
如果要强制释放组件,需要对其调用DisposeOf()
,eg:
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if form4.Components[LIndex] is TVertScrollBox then
begin
form4.Components[LIndex].DisposeOf;
end;
end;
或者,删除活动引用并让 ARC 正常处理销毁:
var
VertScrollLink: TVertScrollBox;
LIndex: Integer;
begin
...
for LIndex := form4.ComponentCount-1 downto 0 do
begin
if form4.Components[LIndex] is TVertScrollBox then
begin
VertScrollLink := TVertScrollBox(form4.Components[LIndex]);
VertScrollLink.Parent := nil;
VertScrollLink.Owner.RemoveComponent(VertScrollLink);
VertScrollLink := nil;
end;
end;
...
end;
也就是说,您可以考虑跟踪您创建的组件,这样您以后就不需要使用循环来查找它了:
type
TForm4 = class(TForm)
procedure FormShow(Sender: TObject);
...
private
VertScrollLink: TVertScrollBox;
...
end;
procedure TForm4.FormShow(Sender: TObject);
begin
VertScrollLink := TVertScrollBox.Create(Self);
VertScrollLink.Align := TAlignLayout.Client;
VertScrollLink.Parent := Self;
end;
begin
...
if Assigned(VertScrollLink) then
begin
VertScrollLink.DisposeOf;
{ or:
VertScrollLink.Parent := nil;
VertScrollLink.Owner.RemoveComponent(VertScrollLink);
}
VertScrollLink := nil;
end;
...
end;