在 Delphi 中释放一个使用引用计数接口创建的窗体的正确方法是什么?

mf98qq94  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(155)

假设我的表单是TFormOther = class(TForm, IMyInterface),其中

type
  IMyInterface = interface
    ['{50E7E215-A8EA-4A1C-9F1E-018E4A76DCBD}']
    procedure DoSomething;
  end;

TFactory = class(TInterfacedObject)
public
  procedure MakeIt;
end;

procedure TFactory.MakeIt;
var
  LMyIntf: IMyInterface;
begin
  LMyIntf :=  TFormOther.Create(nil);

  LMyIntf.DoSomething;

  // (LMyIntf as TFormOther).Free; This is wrong and gives the classic: 
  // FastMM has detected an attemp to use an interface of a freed object.
end;

如果我不释放TFormOther示例,就会泄漏内存。
我知道我可以在TFormOther.FormClose中做Action := TCloseAction.caFree,但这是唯一和最好的方法吗?
这个Will an interface-implementing form free itself when there are no more references to it?帮助很大,但没有说明应该如何释放窗体。

dfty9e19

dfty9e191#

使用(LMyIntf as TFormOther).Free;通过其接口引用直接释放窗体问题是,接口引用将比窗体对象示例寿命长
当该接口超出范围时,在过程结尾部分,编译器插入了对_IntfClear的调用以完成LMyIntf引用,最终将在已销毁的窗体示例上调用_Release方法。
若要避免这种情况,您必须在释放表单之前明确清除界面。这需要额外的对象变数,您可以透过这个变数呼叫Free来释放表单。

procedure TFactory.MakeIt;
var
  LMyIntf: IMyInterface;
  LObj: TObject; 
begin
  LMyIntf :=  TFormOther.Create(nil);

  LMyIntf.DoSomething;

  LObj := TObject(LMyIntf);
  LMyIntf := nil;
  LObj.Free;
end;

当通过FromClose事件处理程序释放窗体时,只有在释放时没有活动接口引用窗体的情况下,这种释放才能完美地工作。讨论通用代码时,很难说哪种方法更好,但是当使用FormClose事件时,可能很难确保此时没有活动接口,并且这样的代码可能更难遵循。

相关问题