Freeing interfaced object that descends from a TRectangle

梦想与她 提交于 2020-01-15 06:58:05

问题


I'm new to interfaces and have been trying them out in my latest project. I have this (simplified) interface:

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

Several classes descend from it like so:

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

I have a factory for creating the shapes in its own data module.

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;

The result is added to a TList<IBoardShape>.

All of this worked well, until I started trying to remove shapes at run time. I found that TList[I] := nil didn't free the item, the control would just stay on the screen. So, from here I'm not sure to do. I found I can cast the object to a TShape and call .Free on it, but that doesn't sound right. (I tried it and it works but then it leads to other problems - errors inside Delphi code when trying to free an interface.)

One thing that I'm not sure about: Since my TGameRectangle doesn't descend from TInterfacedObject, should I be doing my own reference counting? Or am I misunderstanding what TInterfacedObject is for?


回答1:


Yes, if you want to use interfaces and reference counting, you need to either inherit from a type that provides reference counting or provide your own implementations of _AddRef and _Release.

What do the _AddRef and _Release that your TGameRectangle has do?




回答2:


I'm going to restrict my answer to desktop platforms which do not have ARC. That's because on ARC platforms there is nothing to do. The ARC framework will manage lifetime for you and you must not re-implement _AddRef and _Release.

For non-ARC platforms you have a fundamental design problem. You want your object's lifetime to be controlled by two independent mechanisms:

  1. The TComponent owner, and
  2. The interface reference count.

You need to make up your mind to do it one way or the other. But not both.

If you opt for the first option you just need to make sure that you clear the interface reference before the owner is destroyed. Then let the owner destroy your rectangle object.

If you opt for the second option you need to pass nil as the owner parameter of the constructor. And then implement interface reference counted lifetime management as per TInterfacedObject.

A common pattern is to let the value of the owner passed to the constructor determine the lifetime model. So, when the owner is nil, interface reference counting controls the life. Otherwise the owner controls it. The canonical example of this pattern is TXMLDocument.

All that said, I don't think this pattern works at well with visual components. The framework is designed so that visual component lifetime is not controlled by interface reference counting. I think it is folly to go against that design. I suggest you opt for option 1.



来源:https://stackoverflow.com/questions/21770260/freeing-interfaced-object-that-descends-from-a-trectangle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!