【问题标题】:Freeing interfaced object that descends from a TRectangle释放从 Rectangle 继承的接口对象
【发布时间】:2014-02-14 03:23:54
【问题描述】:

我是接口的新手,并且一直在我的最新项目中尝试它们。我有这个(简化的)界面:

IBoardShape = interface(IInterface)
  function GetColor: integer; 
  procedure SetColor(const aColor: integer);
  property Color: integer read GetColor write SetColor;
end;

几个类是这样继承的:

TGameRectangle = class(TRectangle, IBoardShape)
private
  FColor: integer;
  function GetColor: integer;
  procedure SetColor(const aColor: integer);
  property Color: integer read GetColor write SetColor;
end;

我有一个工厂,用于在自己的数据模块中创建形状。

function TdmShapeManager.CreateRect(aParent: TLayout): IBoardShape;
var
  lRect: TGameRectangle;
begin
  lRect := TGameRectangle.Create(self);
  lRect.Parent := aParent; 
  lRect.Align := TAlignLayout.alClient;
  result := lRect as IBoardShape;
end;

结果被添加到TList<IBoardShape>

所有这些都运行良好,直到我开始尝试在运行时删除形状。我发现TList[I] := nil 没有释放该项目,控件只会停留在屏幕上。所以,从这里我不确定。我发现我可以将对象转换为 TShape 并在其上调用 .Free,但这听起来不对。 (我试过了,它可以工作,但它会导致其他问题 - 尝试释放接口时 Delphi 代码中的错误。)

我不确定的一件事:由于我的TGameRectangle 不是来自TInterfacedObject,我应该自己做引用计数吗?还是我误解了TInterfacedObject 的用途?

【问题讨论】:

    标签: delphi interface


    【解决方案1】:

    我的回答仅限于没有 ARC 的桌面平台。那是因为在 ARC 平台上无事可做。 ARC 框架将为您管理生命周期,您不得重新实现_AddRef_Release

    对于非 ARC 平台,您有一个基本的设计问题。您希望对象的生命周期由两种独立的机制控制:

    1. TComponent 所有者和
    2. 接口引用计数。

    您需要下定决心以一种或另一种方式做到这一点。但不是两者兼而有之。

    如果您选择第一个选项,您只需要确保在销毁所有者之前清除接口引用。然后让所有者销毁您的矩形对象。

    如果您选择第二个选项,您需要将nil 作为构造函数的所有者参数传递。然后按照TInterfacedObject实现接口引用计数生命周期管理。

    一种常见的模式是让传递给构造函数的所有者的值决定生命周期模型。因此,当所有者为nil 时,接口引用计数控制生命。否则所有者控制它。这种模式的典型例子是TXMLDocument

    话虽如此,我认为这种模式不适用于视觉组件。该框架的设计使得可视组件的生命周期不受接口引用计数的控制。我认为反对这种设计是愚蠢的。我建议你选择选项 1。

    【讨论】:

      【解决方案2】:

      是的,如果您想使用接口和引用计数,您需要从提供引用计数的类型继承或提供您自己的_AddRef_Release 实现。

      你的 TGameRectangle 中的 _AddRef_Release 有什么作用?

      【讨论】:

      • 我现在两个都没有。我应该通过复制/修改TInterfacedObject 的工作方式来实现它们吗?
      • 我在看这个,我有点困惑。 TGameRectangleTFmxObject 一路下降,这是一个TComponent,在TComponent 中已经有_AddRef_Release。那么我的对象不应该已经有引用计数了吗?
      • 没关系,我把它们放进去,效果很好。感谢您的帮助!
      • 我在我的 Android 设备上运行了它,但它不起作用。我查看了引用计数,它上升到 5,在 Windows 上运行它只有 1,这就是我认为它可以工作的原因。关于为什么会如此不同的任何想法?这可能是一个单独的问题。
      • @Sentient:这可能与 ARC 有关,但您必须将其作为一个不同的问题提出。
      猜你喜欢
      • 2016-02-07
      • 2014-12-24
      • 2011-06-15
      • 2010-10-21
      • 2011-04-15
      • 2013-08-31
      • 1970-01-01
      • 2013-01-24
      • 1970-01-01
      相关资源
      最近更新 更多