ARC自动引用计数与方法function过程procedure的传参的对象类型及其回调值

ARC自动引用计数与方法function过程procedure的传参的对象类型及其回调值

一、ARC自动引用计数:Auto Reference counting 

二、对象类型

任何对象的数据类别,其存在的形式都有四种可能:

2.1、const(显式的常量),即:const L: <T> ;

2.2、var(显式的变量),即:var L: <T> ;

2.3、out(显式的输出),即:out L: <T> ;

2.4、(隐式),即:L: <T> ;

三、对象类型作为参数传递给方法function或过程procedure

对象类型作为参数时,传递的到底是什么:

3.1、const(显式的常量),即:const L: <T> ;  传参传的是L的地址(内存寄存器地址,当L的地址变了,内存寄存器地址也变了,ARC就变了,所以L可以被回调给调用者)

3.2、var(显式的变量),即:var L: <T> ;传参传的是L的地址(内存寄存器地址,当L的地址变了,内存寄存器地址也变了,ARC就变了,所以L可以被回调给调用者)

3.3、out(显式的输出),即:out L: <T> ;传参被屏蔽且其值无须初始化,当L的数值变了,内存寄存器地址不变,但内存寄存器地址的数值被改变,ARC就变了,所以L其数值可以被回调给调用者,但其初始数值不起作用

3.4、(隐式),即:L: <T> ;传参传的是L的数值(该内存寄存器地址的数值,当L的数值变了,内存寄存器地址却没有变,且内存寄存器地址的数值也不会变的,ARC就没有变,所以L不可以被回调给调用者)

所以,需要养成好的代码习惯,使用显式的对象类型或隐式的对象类型!

用于范围:方法function过程procedure均适用。

因而,网上说的:方法function过程procedure的最大区别是,前者能为调用者返回值、后者不能,说法是不确切的!

四、案例

4.1、方法function传参:// program ProgDataDictionary; //unit myFuc_Client;

function UploadNewestSysDb(
  var AResultTips:string;  // :回调的结果提示信息   // : 如果AResultTips:string; 是不会产生回调结果的!
  const APath:string=''; const AFile:string=''
  ):Boolean;

var LJsonFilePath,LPathLocalSysdb,
    LTips,AFileUploadStatus:string;
    LTThread:TThread; //LEvent:TEvent;
begin
  //为了本地系统Db的线程安全和获取UI提示,
    //:无论用线程还是任务(异步任务),均应阻塞方式:
  SubPathOfAppPublished;//:1、产生APP全平台路径
  LJsonFilePath:=GetSubPathOfAppPublished('Upload','files');
  //:2、获取APP全平台路径
  //3、从默认应用程序文件夹复制最新系统Db
    //:(最新的Sqlite3本地系统表和数据字典数据)
    //:到App->Download->files :
  //4、将3复制的最新系统Db文件上传到应用服务器的api目录:
    //while not (ifCreateLocalDataStructure=true) do sleep(0);
  LTips:='';
  //LEvent:=TEvent.Create;
  LTThread:=TThread.CreateAnonymousThread(
  procedure
  begin
    try
      try
        LPathLocalSysdb:=productTextFile('','CarveoutO2O.s3db');
        if TFile.Exists(LPathLocalSysdb)=true then
        begin //:3.1存在文件,执行覆盖复制:
          //TThread.Synchronize(nil, procedure begin Memo1.Lines.Clear;Memo1.Lines.Add(LJsonFilePath+'CarveoutO2O.s3db'); end );
          //:已经包含路径分隔符:System.IOUtils.TPath.DirectorySeparatorChar
          TFile.Copy( LPathLocalSysdb,
            LJsonFilePath+'CarveoutO2O.s3db',
            true );
        end else
        begin
          LTips:='本地系统数据库文件不存在';
          exit;
        end;
      finally
        //4.1、将复制的文件上传至应用服务器的api目录
        while TFile.Exists(LJsonFilePath+'CarveoutO2O.s3db')=false do sleep(0);
        if TFile.Exists(LJsonFilePath+'CarveoutO2O.s3db')=true then
        begin
          AFileUploadStatus:=
            RestUploadFiles('','',(ExtractFilePath(LJsonFilePath))
              ,(ExtractFileName('CarveoutO2O.s3db')),(13*1024*1024)
              ,'api\upload\',(ExtractFileName('CarveoutO2O.s3db'))
              ,'非压错包内含压错包');
          //这个场景必须等待确保上传成功,否则不停地点击会造成
            //上一次点击的文件被占用和调用服务的IP地址的socket占用尚未结束!
            //一直等待上一个文件上传成功结束:
          LTips:=AFileUploadStatus;
        end;
      end;
    except
      //LEvent.Free;
      LTips:='文件上传异常';
    end;
    //LEvent.SetEvent;
  end );
  LTThread.FreeOnTerminate:=true;//:可有可无,匿名线程当有任何其它线程(包括UI线程)执行时会自动释放,见
  LTThread.Start;
  while not(LTThread.Finished) do begin //:阻塞UI,等价于:
  //while LTips.Trim='' do sleep(0);//:阻塞UI,等价于:
  //if (LEvent.WaitFor(INFINITE)=TWaitResult.wrSignaled) then //:0:等不来提示,也不会释放事件AEvent:INFINITE
    //LEvent.Free;
    AResultTips:=LTips;//:回调形参变量:ARC赋值其地址(自动引用计数)
    if LTips.Trim='文件上传成功' then
    begin
      Result:=true;
    end else
    begin
      Result:=false;
    end;
  end;
end;

// 调用:// program ProgDataDictionary; //unit Dictionary;

procedure TfmxDictionary.btnPostDataClick(Sender: TObject);
var LTips:string;
begin
  if not(ifCreateLocalDataStructure=true) then
  begin //:ifCreateLocalDataStructure是否存在sqlite3批量写操作完成
    TextTips.Text:='数据正在批量写入,请稍后再试!';
    RectTips.Visible:=true;
    exit;
  end else  //上传最新本地sqlite3系统Db到应用服务器api目录:
  if UploadNewestSysDb(LTips,'','')=true then  //: 回调LTips,显示给UI
  begin
    TextTips.Text:=LTips;
    RectTips.Visible:=true;
  end;
end;

4.2、过程procedure传参:// program DepartmentsServerProject; //unit ServerMethodsUnit1;;

procedure TServerMethods1.ProduceAbigTFDJSONDataSets(
  const LFDJSONDataSets:TFDJSONDataSets;       //:回调const LFDJSONDataSets给调用者  //LFDJSONDataSets:TFDJSONDataSets;不会产生回调结果
  const DatasTab1Key,DatasTab1Sql,//:数据表对象1
  DatasTab2Key,DatasTab2Sql, //:数据表对象2
  DatasTab3Key,DatasTab3Sql:string  //:数据表对象3
);

var dispLog:string; LFDQuery1,LFDQuery2,LFDQuery3:TFDQuery;
  LFDJsonWrit:TFDJsonDatasetsWriter;
begin
  //Encoding := TEncoding.GetEncoding('GB2312');//:无需:TFDJsonDatasets已经Encoding啦

  LFDQuery1:=TFDQuery.Create(FDConGlobal);//:FDConGlobal:池化的连接
  LFDQuery1.Connection:=FDConGlobal;
  LFDQuery1.FetchOptions.Mode:=fmAll;
  LFDQuery1.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery1.FetchOptions.RowsetSize:=9999999;
  LFDQuery1.FetchOptions.RecsMax:=-1;
  LFDQuery1.FetchOptions.RecsSkip:=-1;

  LFDQuery2:=TFDQuery.Create(FDConGlobal);
  LFDQuery2.Connection:=FDConGlobal;
  LFDQuery2.FetchOptions.Mode:=fmAll;
  LFDQuery2.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery2.FetchOptions.RowsetSize:=9999999;
  LFDQuery2.FetchOptions.RecsMax:=-1;
  LFDQuery2.FetchOptions.RecsSkip:=-1;

  LFDQuery3:=TFDQuery.Create(FDConGlobal);
  LFDQuery3.Connection:=FDConGlobal;
  LFDQuery3.FetchOptions.Mode:=fmAll;
  LFDQuery3.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery3.FetchOptions.RowsetSize:=9999999;
  LFDQuery3.FetchOptions.RecsMax:=-1;
  LFDQuery3.FetchOptions.RecsSkip:=-1;
  try
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin //数据表对象1
        dispLog:=DatasTab1Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab1Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        LFDQuery1.DisableControls;
        LFDQuery1.SQL.Text :=dispLog;
        LFDQuery1.EnableControls;
        LFDQuery1.Active :=True;//LFDQuery1.Open;//:都可以
        while LFDQuery1.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 主表记录数:'+IntToStr(LFDQuery1.RecordCount) );
        //MainServerForm.Memo_Errors.Lines.Add('-- 测试主表记录字段值:'+LFDQuery1.FieldByName(LFDQuery1.FieldDefs[3].name).AsString.Trim );
      end;
    finally
    end;
    try
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin //数据表对象2:
        dispLog:=DatasTab2Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab2Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        LFDQuery2.DisableControls;
        LFDQuery2.SQL.Text :=dispLog;
        LFDQuery2.EnableControls;
        LFDQuery2.Active :=True;
        while LFDQuery2.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 从表记录数:'+IntToStr(LFDQuery2.RecordCount) );
      end ;
    finally
    end;
    try
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin //数据表对象3:
        dispLog :=DatasTab3Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab3Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        LFDQuery3.DisableControls;
        LFDQuery3.SQL.Text :=dispLog;
        LFDQuery3.EnableControls;
        LFDQuery3.Active :=True;
        while LFDQuery3.State=dsInactive do sleep(0);
      end ;
    finally
    end;
    LFDJsonWrit:=TFDJsonDatasetsWriter.Create(LFDJsonDatasets);
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        while LFDQuery1.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab1Key,LFDQuery1 );
      end;
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        while LFDQuery2.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab2Key,LFDQuery2 );
      end;
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        while LFDQuery3.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab3Key,LFDQuery3 );
      end;
    finally
    end;

  finally
    FreeAndNil(LFDJsonWrit);
    //释放它们就是在释放数据库连接:交给池//:LFDQuery1.Free;  LFDQuery2.Free;  LFDQuery3.Free;

  end;
end;

// 调用:// program DepartmentsServerProject; //unit ServerMethodsUnit1;

function TServerMethods1.getTablesStruct:TJSonObject;
//:Rest请求数据库服务器执行用户表列表的表CtL00001及其表结构的表DataDictionary保持最新
var LJSonString:string;  //LEncoding:TEncoding;
var LFDJsonDatasets :TFDJsonDatasets;
  ifFinished:Boolean; LFDJSONInterceptor:TFDJSONInterceptor;
  LDatasTab1Key,LDatasTab1Sql:string;//:数据表对象1
  LDatasTab2Key,LDatasTab2Sql:string; //:数据表对象2
  LDatasTab3Key,LDatasTab3Sql:string;  //:数据表对象3
  UseBoolStrs: TUseBoolStrs;
begin
  //LEncoding:=TEncoding.GetEncoding('GB2312'); //LEncoding.GetString( //LEncoding.GetBytes( //UTF8String(LJSonString)
  //:执行特定的存储过程(内部不涉及com_id的处理)sp_getTablesStruct:
  LFDJsonDatasets := TFDJsonDatasets.Create;
  LFDJSONInterceptor:=TFDJSONInterceptor.Create;
  Result:=TJSonObject.Create;
  try
    LJSonString:=performStoreProc('sp_getTablesStruct','001',LJSonString);
    if LJSonString.Trim='处理表结构成功' then
    begin
      //TThread.Synchronize(nil,procedure begin
        //MainServerForm.Memo_Errors.Lines.Add('处理表结构成功'); end );
      try
        LDatasTab1Key:='CtL00001';
        LDatasTab1Sql:='select * from CtL00001 '
          +' where (ltrim(rtrim(coalesce(c_tablename,'''')))<>''Data_Report_Customize_Sales_ItemtypeAndRegionalism'') '
          +'   and (ltrim(rtrim(coalesce(c_tablename,'''')))<>''Data_Report_Customize_Sales_vendorIDtypeIDAndRegionalism'') '
          +'   and (ltrim(rtrim(coalesce(c_tablename,'''')))<>''Customize_Sales_ItemtypeAndRegionalism'') '
          +'   and (ltrim(rtrim(coalesce(c_tablename,'''')))<>''Customize_Sales_vendorIDtypeIDAndRegionalism'') '
          +' order by c_tablename ';//:数据表对象1
        LDatasTab2Key:='DataDictionary';
        LDatasTab2Sql:='select * from DataDictionary order by c_tablename,FieldID'; //:数据表对象2
        LDatasTab3Key:=''; LDatasTab3Sql:='';  //:数据表对象3
        //此处用过程传参获取LFDJsonDatasets:
          //:切忌使用方法返回TFDJsonDatasets:
            //:否则返回时内存泄漏你永远释放不掉这个TFDJsonDatasets实例
              //:function TServerMethods1.GetAbigTFDJSONDataSets:(内存泄漏)
                //内存泄漏:
              //LFDJsonDatasets:=
                //GetAbigTFDJSONDataSets(
                  //LDatasTab1Key,LDatasTab1Sql,
                  //LDatasTab2Key,LDatasTab2Sql,
                  //LDatasTab3Key,LDatasTab3Sql );
            //:因为方法返回TFDJsonDatasets对象是为远程客户端调用准备的:
              //:它的释放是在客户端代理TServerMethods1Client中进行的:unit ClientClassesUnit1;:
                //:用Datasnap.DSProxyRest.TDSRestClient判断客户端进行实例化调用后
                //:再用Datasnap.DSClientRest.TDSRestCommand在客户端进行释放FreeOnExecute的
                //if FInstanceOwner then FGetAbigTFDJSONDataSetsCommand.FreeOnExecute(Result);
          ProduceAbigTFDJSONDataSets(LFDJsonDatasets,
            LDatasTab1Key,LDatasTab1Sql,
            LDatasTab2Key,LDatasTab2Sql,
            LDatasTab3Key,LDatasTab3Sql );//:procedure显式传参:TFDJsonDatasets//:显式传参申请获取回调LFDJsonDatasets
        ifFinished:=LFDJSONInterceptor.DataSetsToJSONObject(
          LFDJsonDatasets,
          Result );  //:显式传参LFDJsonDatasets申请获取自身返回值Result
        while ifFinished=false do sleep(0);
        if ifFinished=true then
        TThread.Synchronize(nil,procedure begin
          MainServerForm.Memo_Errors.Lines.Add('执行了获取数据集列表'); end );
      finally
        FreeAndNil(LFDJsonDatasets);  //得到释放
      end;
    end;
  finally
    LFDJSONInterceptor.Free; 
  end;

end;

而:TFDJSONInterceptor.DataSetsToJSONObject也是以显式const ADataSets: TFDJSONDataSetsBase;传参的:

// Converts dataset list into json
class function TFDJSONInterceptor.DataSetsToJSONObject(
  const ADataSets: TFDJSONDataSetsBase;
  const AJSONObject: TJSONObject): Boolean;
begin
  Result := ItemListToJSONObject(ADataSets.FDataSets, AJSONObject);
end;

发布了61 篇原创文章 · 获赞 6 · 访问量 5576

猜你喜欢

转载自blog.csdn.net/pulledup/article/details/102646822