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;