用接口管理对象的生命周期.

简介: 为什么用接口老是会AV错误?可能很多人会碰到这样的问题。 有些人干脆抛弃用接口来管理对象的生命周期。 我想如果搞清楚接口何时会增加和减少计数应该会掌控到接口何时会销毁对象从而解决av根本。 做了一个测试 procedure TForm1.

为什么用接口老是会AV错误?可能很多人会碰到这样的问题。

有些人干脆抛弃用接口来管理对象的生命周期。

我想如果搞清楚接口何时会增加和减少计数应该会掌控到接口何时会销毁对象从而解决av根本。

做了一个测试

image

procedure TForm1.btnAddInterfaceClick(Sender: TObject);
var
  lvITest: ITest;
begin
  //+1
  lvITest := TTestIntfObject.Create;
  //+1
  FVIList.Add('abc', lvITest);
  //-1
  lvITest := nil;
end;

 

FVIList是自己写的一个接口管理对象,

*****在这里来讨论下局部变量lvITest,lvITest属于局部变量。即使没有最后一句lvITest :=nil;在该函数运行完成时也会隐含的执行lvItest:=nil;也就是说该对象的FRefCount 还是=1;

 

//假如下面代码会释放接口对象.

FVIList.Remove('abc');

//下面方法是非常正确的使用接口工作的一种方法

procedure TForm1.btnUseInterfaceClick(Sender: TObject);
var
  lvIntf: ITest;
  lvIntf2: IInterface;
begin
  //正常
  //+1
  lvIntf2 := FVIList.GetInterfaceByKey('abc');
  //+1
  lvIntf := (lvIntf2 as ITest);
  lvIntf.showMessage;
  //-1
  lvIntf := nil;
  //-1
  lvIntf2 := nil;

  //-1
  FVIList.Remove('abc');
end;

 

//还有一种情况,我们可能会经常这样使用

procedure TForm1.btnUseInterfaceClick(Sender: TObject);
var
  lvIntf: ITest;
begin
   //+1 +1  //这样获取接口会使FRefCount +2
   lvIntf := (FVIList.GetInterfaceByKey('abc') as ITest);
   lvIntf.showMessage;
   //-1  -这里只减1,还有一次会在该函数执行完成时隐含执行
   lvIntf := nil;
  

   //-1  如果下面代码对对象进行了手工释放。就会出现AV错误了。

   //当然可以不在这里进行Remove

   FVIList.Remove('abc');
end;

 

 

//

procedure TForm1.btnRemoveClick(Sender: TObject);
begin
  FVIList.Remove('abc');
end;

 

----------------------------------------------------------------

//下面再看一个过程

procedure TForm1.btnUseInterface2Click(Sender: TObject);
var
  lvIntf, lvIntf2: ITest;
  lvTest: TTestIntfObject;
  lvVIList:TVIList;
begin
  lvVIList := TVIList.Create(false); //不使用List管理接口对象生命周期(false)

  //+0  //创建对象不增加
  lvTest := TTestIntfObject.Create;

  //+1
  lvIntf := lvTest;

  //+1
  lvVIList.Add('abc', lvIntf);


  //-1
  lvIntf := nil;

  //+1 +1
  lvIntf2 := (lvVIList.GetInterfaceByKey('abc') as ITest);
  lvIntf2.showMessage;
  //-1
  lvIntf2 := nil;

  //-1 
  lvVIList.Remove('abc');

  lvVIList.Free;

 

  //这里进行释放是会出现错误的因为还有一个隐含的接口没有进行释放

//procedure TInterfacedObject.BeforeDestruction;
//begin
//  if RefCount <> 0 then
//  begin
      //还存在引用对象的接口没有释放!
//    Error(reInvalidPtr);
//  end;
//en

  lvTest.Free;
end;

 

 

//////

procedure TVIList.Add(pvKey: string; const pvInterface: IInterface);
begin
  //加上const因为内部不能赋值接口所以没有必要+1
  //如果参数pvInterface没有const //+1
  if FVIObject.O[pvKey] <> nil then raise Exception.CreateFmt('%s已经注册接口', [pvKey]);
  //+0
  FVIObject.I[pvKey] := Integer(pvInterface);

  //+1
  pvInterface._AddRef; //引用

  //如果参数pvInterface没有const //-1
end;

目录
相关文章
|
1月前
|
XML Java 数据格式
SpringBean的生命周期
SpringBean的生命周期
28 0
|
2月前
|
缓存 JavaScript
onActivated 生命周期的使用和介绍
onActivated 生命周期的使用和介绍
41 3
|
4月前
将生命周期方法添加到类中
将生命周期方法添加到类中
|
4月前
|
容器
IOC容器初始化过程中单例Bean的预实例化
IOC容器初始化过程中单例Bean的预实例化
29 0
|
7月前
IT服务生命周期
IT服务生命周期
149 0
|
9月前
|
XML Java 数据格式
SpringBean生命周期
SpringBean生命周期
|
12月前
|
前端开发 Java 数据库连接
【SSM】Bean 作用域和生命周期(重点:Bean 的生命周期5大部分)
本文重点介绍Bean 的 6 种作用域singleton、prototype、request、session、application、websocket:HTTP和Bean 的生命周期5大部分。
102 0
|
存储 安全 Java
|
Java Spring 容器
Spring框架:第三章:对象的生命周期及单例bean生命周期的11个步骤
Spring框架:第三章:对象的生命周期及单例bean生命周期的11个步骤
|
XML 缓存 Java
SpringBean(配置、实例化、作用域、生命周期、装配方式)
SpringBean(配置、实例化、作用域、生命周期、装配方式)
129 0
SpringBean(配置、实例化、作用域、生命周期、装配方式)