1

首先,大家好,感谢您的帮助。

我正在尝试使用接口在 Delphi 中实现观察者模式,因此对象可以同时是主题和观察者。

我有一个实现 ISubject 的类,方法如下:

procedure TSomeClass.Attach(const observer: IObserver);
var
  I: Integer;
begin
  if Fobservers = nil then
  begin
    Fobservers := TInterfaceList.Create;
  end;
  if Fobservers.IndexOf(Observer) < 0 then
    Fobservers.Add(Observer);
end;

我在http://blogs.teamb.com/joannacarter/2004/06/30/690上遵循了 Joanna Carter 的示例。

在应用程序中,我实例化了一个实现 IObserver 的对象,并将它附加到 TSomeClass 对象(它也实现了 ISubject)。

然后我从 TSomeClass 对象调用 Notify 方法,它可以正常工作。当我尝试 FreeAndNil 我的 Observer 对象时出现我的问题,因为我得到一个无效的指针操作,即使我在参数中使用“const”并且当我在调试模式下到达 FreeAndNil 行时,对象被正确分配,所有属性设置,并在通知内更改了随机属性。

我注意到,当我调用此行时,我不能再释放我的对象了:

Fobservers.Add(Observer);

如果我评论这一行,那么我可以释放我的对象。应用程序内部的代码如下所示:

procedure TfrmAlisson.Button2Click(Sender: TObject);
var
  locSomeClass: TSomeClass;
  locObserver: TSomeObserverClass;
  I: Integer;
begin
  locObserver:= TSomeObserverClass.create(394693);
  try
    locSomeClass:= TSomeClass.create(263151);
    try
      locSomeClass.Attach(locObserver);
      locSomeClass.NotifyObservers;
    finally
      FreeAndNil(locSomeClass);
    end;
    ShowMessage(IntToStr(locObserver.SomeProperty)); // This property is changed inside the notify
  finally
    locObserver.Free; // error
  end;
end;

我想知道为什么将 IObserver 添加到 TInterfaceList 会导致这种情况(我使用的是 Delphi 2009)。

4

1 回答 1

3

TSomeObserverClass很可能继承自TInterfacedObject.

当你传入它时,Attach它会被传递IObserver,这就是引用计数开始的地方。当它被添加时,RefCount 变为 1 Fobservers,当你销毁locSomeClass它时,Fobservers它会再次被删除,这导致 RefCount 下降到 0 . 然后接口引用后面的实例IObserver正在被销毁。

为了显示这里的问题是重现它的最少代码:

var
  obj: TInterfacedObject;
  list: TInterfaceList;
begin
  o := TInterfacedObject.Create;
  try
    list := TInterfaceList.Create;
    list.Add(o);
    list.Free;
  finally
    FreeAndNil(o);
  end;
end;

如果执行此操作,您会在 FreeAndNil 中看到 EInvalidError,这是因为实例已被TInterfacedObject.

正如已经评论过的,您不应该混合对象和接口引用从不实现自动引用计数的类继承。

于 2013-09-11T06:27:57.277 回答