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

简介: 为什么用接口老是会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;

目录
相关文章
|
8月前
|
XML Java 数据格式
SpringBean的生命周期
SpringBean的生命周期
81 0
|
2月前
|
应用服务中间件
生命周期
Servlet接口中一共是5个方法,其中有三个是生命周期方法。 Ø void init(ServletConfig):这个方法会在Servlet被创建后,马上被调用。只会被调用一次!我们可以把一些初始化工作放到这个方法中,如果没有什么初始化工作要做,那么这个方法就空着就可以了。 ² Servlet有两个时间点会被创建:一是在第一次被请求时,会被创建;二是Tomcat启动时被创建,默认是第一种,如果希望在tomcat启动时创建,这需要在web.xml中配置。 Ø void destroy():这个方法会在Servlet被销毁之前被调用。如果你有一些需要释放的资源,可以在这个方法中完成,如果
|
5月前
NettyHandler 常用生命周期方法
NettyHandler 常用生命周期方法
38 0
|
8月前
|
缓存 JavaScript
onActivated 生命周期的使用和介绍
onActivated 生命周期的使用和介绍
464 3
|
8月前
将生命周期方法添加到类中
将生命周期方法添加到类中
|
Java 容器 Spring
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
IT服务生命周期
IT服务生命周期
384 0
|
XML Java 数据格式
SpringBean生命周期
SpringBean生命周期
|
前端开发 Java 数据库连接
【SSM】Bean 作用域和生命周期(重点:Bean 的生命周期5大部分)
本文重点介绍Bean 的 6 种作用域singleton、prototype、request、session、application、websocket:HTTP和Bean 的生命周期5大部分。
179 0
|
存储 安全 Java