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

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

目录
相关文章
|
6月前
|
XML Java 数据格式
SpringBean的生命周期
SpringBean的生命周期
64 0
|
6天前
|
应用服务中间件
生命周期
Servlet接口中一共是5个方法,其中有三个是生命周期方法。 Ø void init(ServletConfig):这个方法会在Servlet被创建后,马上被调用。只会被调用一次!我们可以把一些初始化工作放到这个方法中,如果没有什么初始化工作要做,那么这个方法就空着就可以了。 ² Servlet有两个时间点会被创建:一是在第一次被请求时,会被创建;二是Tomcat启动时被创建,默认是第一种,如果希望在tomcat启动时创建,这需要在web.xml中配置。 Ø void destroy():这个方法会在Servlet被销毁之前被调用。如果你有一些需要释放的资源,可以在这个方法中完成,如果
|
1月前
|
XML Java 数据格式
必知必会的13个Bean生命周期处理机制:深入理解与实践
【10月更文挑战第15天】在Spring框架中,Bean的生命周期是一个至关重要的概念,它涵盖了从Bean的创建、初始化、使用到销毁的全过程。对于一名资深的架构师而言,深入理解和掌握Bean生命周期的每一个处理机制,是构建健壮、高效和可维护应用程序的基础。本文将详细介绍Bean生命周期的13个处理机制,并通过实战demo示例来加深理解。
24 1
|
3月前
NettyHandler 常用生命周期方法
NettyHandler 常用生命周期方法
28 0
|
6月前
|
缓存 JavaScript
onActivated 生命周期的使用和介绍
onActivated 生命周期的使用和介绍
401 3
|
6月前
将生命周期方法添加到类中
将生命周期方法添加到类中
IT服务生命周期
IT服务生命周期
346 0
|
XML Java 数据格式
SpringBean生命周期
SpringBean生命周期
|
存储 安全 Java
|
XML 缓存 Java
SpringBean(配置、实例化、作用域、生命周期、装配方式)
SpringBean(配置、实例化、作用域、生命周期、装配方式)
165 0
SpringBean(配置、实例化、作用域、生命周期、装配方式)