【问题标题】:Delphi release interface pointerDelphi 发布接口指针
【发布时间】:2018-03-04 22:49:50
【问题描述】:

我在 Delphi 的接口上苦苦挣扎。这个问题可能是微不足道的,但我是德尔福的新手,所以请原谅。

我有一个带有自定义节点的 TreeView,它拥有一个对象接口(本质上,就像这里建议的那样:Storing interface pointer inside tree view nodes)。

问题是,一旦我删除了一个节点(为了重绘树视图)并将接口变量设置为 nil(由于某种我还没有完全理解的原因,释放不会与接口有关),最奇怪的事情就会发生:

在我的对象中,它包含一个列表、一个整数和一个字符串变量,字符串和列表将设置为空,而整数保持不变。

我无法解释。有没有人知道解决方法,或者这种行为的可能原因?顺便说一句,我使用的是 Delphi 10.2 Tokyo。

这是我相当不起眼的销毁方法:

myNode.destroy;
begin
  intf:= nil;// intf holds the interface to the object
end;

编辑:这是我的代码的简化版本:

我指的对象:(我有几个类似的类,看起来像obj,但略有不同,不知道接口中会存储哪一个,但都共享这些变量)

Obj = class(InterfacedObject, IMyinterface)
  count: integer;  //this remains the same
  children: array of ChildObj;  //this will be emptied
  name: string;  //this will be set to ''
  procedure addChild;
  procedure IMyInterface.add = addChild;
end;

我的自定义树节点:

MyNode = class(TTreeNode)
  Intf: IMyinterface;
  destructor destroy; override;
end;

在我的班级里面管理着 TreeView:

MyForm.ReloadTree;
begin
  if myTreeView.Items.Count > 0 then
  begin
    myTreeView.Items.Clear;
  end
  for I:= 0 to RootObj.Count-1 do
  begin
    myTreeView.Items.AddChild(MyTreeview.Items[0], RootObj.Children[i].name);
    (myTreeView.Items[0][i] as MyNode).Intf := Intf(RootObj.Children[i]);
    //I will proceed iterating over all children and their children, doing 
    //the same process, a level higher in the treeView
    //...
  end;
end;

【问题讨论】:

  • 哦,我的目标是根本不改变对象,因为我仍然需要它
  • 删除节点即可。内部数据在 TTreeNode 析构函数中被“取消”(至少在 VCL 中)。这应该减少接口对象的引用计数并释放它。
  • 请发布minimal reproducible example 准确显示您的代码(不是其他人的代码)如何创建您的节点并为它们分配接口。
  • 请将你的代码正确粘贴到q中,不要放像MyForm.ReloadTree; begin [...]这样的废话,连编译都不会,更别提执行了。

标签: delphi interface treeview delphi-10.2-tokyo


【解决方案1】:

在我的对象中,它包含一个列表、一个整数和一个字符串变量,字符串和列表将被设置为空,而整数保持不变。

这是完全正常的行为。字符串和接口是编译器管理的类型。整数不是。当一个对象被破坏时,编译器管理的数据成员会根据需要自动释放,在字符串和接口的情况下,这涉及到将指向其引用数据的指针归零。包含对象本身并未完全清零,因此非托管类型(如整数)不会在内存中被覆盖。

现在,话虽如此,我在您的ReloadTree() 程序中发现了一些错误。

  1. 您的for 循环超出了RootObj.Children[] 列表的上限。

  2. 调用AddChild()时,第二个参数是string。您在该参数中传递RootObj.Children[i]。但是,在下一个语句中,您在分配 MyNode.Intf 字段时将相同的 RootObj.Children[i] 值类型转换到接口。 string 不是接口。那么,RootObj.Children[] 究竟包含什么 - 字符串或接口?

  3. 分配MyNode.Intf 字段时,您始终访问的是TreeView 中的第一个节点,而不是新添加的节点。

【讨论】:

  • 谢谢,这解释了为什么会发生。无论如何,我可以在销毁接口时防止“归零”吗?
  • @zink 不,你为什么要这样做?你到底想解决什么问题?
  • 哦,是的,您对错误的看法是正确的,很抱歉我没有可用的代码,所以我只是快速重新输入了我记忆中的内容。实际代码避免了所有这些问题:)
  • 而我想做的是让用户通过添加、删除和编辑 obj 对象来管理数据,这些数据非常像树一样结构化。我想我可以用树视图做到这一点。问题是我有时需要重绘我的数据,因为当它所代表的某些数据损坏时,我想更改分支的颜色。除了删除和重绘相应的节点之外,我还没有找到管理它的方法。这将导致我的对象被更改为所描述的。
猜你喜欢
  • 2012-08-28
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
相关资源
最近更新 更多