我的目标是,得到一个设置界面,持有我的应用程序设置的信息.这可能是信息,只有当应用程序运行时才相关,信息应该是永久性的。为此,我认为这将是一个好主意,创建一个应用程序界面和一个持久设置界面内的应用程序设置界面,所以我可以之间切换让我们说INI文件,DB,加密文件,无论什么....之后代码工作,我认为。但在关闭FastMM时,我在TiniFile中留下了内存泄漏,我不知道为什么。下面是带有类的接口单元。
unit UAPPSettings;
interface
uses
IniFiles;
type
IPersistentSettings = Interface
['{11542859-DEA3-4DBB-9A88-2068E407552C}']
function ReadString(Section, Name, Default: String): string;
procedure WriteString(Section, Name, Default: String);
function ReadPassword: string;
procedure WritePassword(Password: String);
end;
type
IAppSettings = Interface
['{559B8219-7D81-44CA-87A0-6D261B4A87E7}']
function GetPersistentSettings: IPersistentSettings;
property PersistentSettings: IPersistentSettings read GetPersistentSettings;
End;
type
TAppSettings = class(TInterfacedObject, IAppSettings)
strict private
FPersistentSettings: IPersistentSettings;
function GetPersistentSettings: IPersistentSettings;
procedure SetPersistentSettings(const Value: IPersistentSettings);
property PersistentSettings: IPersistentSettings read GetPersistentSettings write SetPersistentSettings;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
constructor create(aPersistentSettings: IPersistentSettings);
end;
type
TIniSettings = class(TInterfacedObject, IPersistentSettings)
strict private
FIniFile: TIniFile;
FfilePath: String;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
function ReadString(Section, Name, Default: String): string;
procedure WriteString(Section, Name, Default: String);
function ReadPassword: string;
procedure WritePassword(Password: string);
public
constructor create(FilePath: String);
end;
var
APPSettings: IAppSettings;
implementation
uses
FMX.Types;
{ TIniSettings }
constructor TIniSettings.create(FilePath: String);
begin
FfilePath := FilePath;
end;
function TIniSettings.ReadPassword: string;
begin
Result := ReadString('App', 'Passwort', '');
end;
function TIniSettings.ReadString(Section, Name, Default: String): string;
begin
If FIniFile.ValueExists(Section, Name) = false then
WriteString(Section, Name, Default);
Result := FIniFile.ReadString(Section, Name, Default);
end;
procedure TIniSettings.WritePassword(Password: string);
begin
WriteString('App', 'Passwort', Password);
end;
procedure TIniSettings.WriteString(Section, Name, Default: String);
begin
FIniFile.WriteString(Section, Name, Default);
end;
function TIniSettings._AddRef: Integer;
begin
log.d('IniSettings _AddRef');
FIniFile := TIniFile.create(FfilePath);
Result := inherited _AddRef;
end;
function TIniSettings._Release: Integer;
begin
log.d('IniSettings _Release');
Result := inherited _Release;
FIniFile.Free;
FIniFile := nil;
end;
{ TAppSettings }
constructor TAppSettings.create(aPersistentSettings: IPersistentSettings);
begin
FPersistentSettings := aPersistentSettings;
end;
function TAppSettings.GetPersistentSettings: IPersistentSettings;
begin
Result := FPersistentSettings;
end;
procedure TAppSettings.SetPersistentSettings(const Value: IPersistentSettings);
begin
FPersistentSettings := Value;
end;
function TAppSettings._AddRef: Integer;
begin
log.d('AppSettings _AddRef');
Result := inherited _AddRef;
end;
function TAppSettings._Release: Integer;
begin
log.d('AppSettings _Release');
Result := inherited _Release;
FPersistentSettings := nil;
end;
end.
下面是我创建Object的方法:
APPSettings := TAppSettings.create(TIniSettings.create(System.IOUtils.TPath.GetDocumentsPath + System.SysUtils.PathDelim + 'config.ini'));
任何更好的编码建议,以及真的很感激
1条答案
按热度按时间tpgth1q71#
代码中的问题是,您使用
_AddRef
和_Release
方法的目的不是对调用这两个方法的示例进行内存管理。以下代码是问题的原因:
您正在
_AddRef
方法中构造FIniFile
示例,这是错误的位置,并且_Release
是释放FIniFile
的错误位置。_AddRef
和_Release
方法可以在示例生命周期内多次调用,每次调用_AddRef
都会导致新的TIniFile
示例的构建。为了正确的内存管理,这两个方法将被调用相同的次数,但是
_AddRef
可能会连续被调用多次,然后根据代码的不同,在未来的某个时间会有多个_Release
调用。换句话说,以下序列也是可能的:
或
当你调用
APPSettings := TAppSettings.create(TIniSettings.create(...
first _AddRef
时,当示例作为aPersistentSettings
参数传递时会被调用,因为它没有被声明为const。然后,在将aPersistentSettings
分配给FPersistentSettings
时,将调用下一个_AddRef
,第二次调用将创建TIniFile
示例的泄漏。在构造函数调用结束时,将有
aPersistentSettings
参数_AddRef
调用的匹配_Release
调用。这也将释放ini文件,并且FIniFile
将是nil
并且不可用,直到您再次触发FPersistentSettings
示例上的引用计数。你可以在
TIniSettings
构造函数中创建FIniFile
,然后在它的析构函数中销毁它,或者在TIniSettings
中引入额外的方法(Open/Close
),如果你不想一直创建那个ini文件,你可以在任何阅读或写操作中调用它们。当你从
_AddRef
和_Release
中删除与ini文件相关的代码时,你不再需要在你的类中实现它们,因为默认实现将完成这项工作。有一种额外的方法可以修复代码,即只在
_AddRef
中没有赋值的情况下创建TIniFile
,但是引用计数方法仍然是错误的地方,因为你必须确保你不会在错误的地方意外触发额外的引用计数,这可能会在你仍然需要它的时候给你留下nilFIniFile
变量。