【问题标题】:Using TStringList.AddObject in Delphi Android FMX在 Delphi Android FMX 中使用 TStringList.AddObject
【发布时间】:2020-10-16 06:52:26
【问题描述】:

我正在为 Android 编译的 Delphi 10.3.3 应用程序中有一个 FMX TCombobox。我之前研究过这个主题,发现Using Primitive Types with TStrings in iOS。我下载了BoxPrimitives.pas和下面的代码,在Delphi 10.3.3下编译成功。

uses BoxPrimitives;

{$ifdef ANDROID}
cbGender.Items.AddObject('Male', TBoxInteger(1));
cbGender.Items.AddObject('Female', TBoxInteger(0));
{$else}
cbGender.Items.AddObject('Male', TObject(1));
cbGender.Items.AddObject('Female', TObject(0));
{$endif}

现在我在 Delphi 10.4.1 中打开了该源代码,BoxPrimitives.Pas 不再编译。

[DCC 错误] BoxPrimitives.pas(46): E2123 PROCEDURE, FUNCTION, PROPERTY 或 VAR 预期

那么一般的问题是:Delphi 10.4 中的哪些变化阻止了它的编译?更具体地说:在 Delphi 10.4 中,有没有办法在 Android 中使用 AddObjectTCombobox

【问题讨论】:

  • 10.4 不再有 ARC 编译器,Windows 代码应该可以在 Android 上再次运行。

标签: android delphi firemonkey


【解决方案1】:

在 RAD Studio 10.4 中,Embarcadero 决定在其移动平台上删除 ARC for object lifetime management

What's New in RAD Studio 10.4 Sydney

统一内存管理

  • Delphi 内存管理现在在所有受支持的平台(移动、桌面和服务器)上统一 - 使用对象内存管理的经典实现。与自动引用计数 (ARC) 相比,这为现有代码提供了更好的兼容性,并且为组件、库和最终用户应用程序提供了更简单的编码。 ARC 模型仍然用于所有平台的字符串管理和接口类型引用。

  • 对于 C++,此更改意味着在 C++ 中创建和删除 Delphi 风格的类就像任何堆分配的 C++ 类一样遵循正常的内存管理,从而显着降低了复杂性。

在所有 Delphi 编译器版本和平台上检测何时使用 ARC 对象生命周期管理的正确方法是使用 {$IFDEF AUTOREFCOUNT}BoxPrimitives.pas 单元中甚至提到了这一点:

该类仅供 AUTOREFCOUNT 编译器使用

例如:

{$ifdef AUTOREFCOUNT}
uses BoxPrimitives;
{$endif}

{$ifdef AUTOREFCOUNT}
cbGender.Items.AddObject('Male', TBoxInteger(1));
cbGender.Items.AddObject('Female', TBoxInteger(0));
{$else}
cbGender.Items.AddObject('Male', TObject(1));
cbGender.Items.AddObject('Female', TObject(0));
{$endif}

...

var Value: Integer;
{$ifdef AUTOREFCOUNT}
Value := TBoxInteger(cbGender.Items.Objects[index]);
{$else}
Value := Integer(cbGender.Items.Objects[index]);
{$endif}

话虽如此,我可能会更进一步,通过编辑BoxPrimitives.pas 以用{$IFDEF AUTOREFCOUNT} ... {$ELSE} ... {$ENDIF} 包围其代码,然后在{ELSE} 部分中将TBoxInteger(和其他类型)定义为简单别名,例如:

interface

{$ifdef AUTOREFCOUNT}

uses
  Classes, Types, Generics.Defaults;

type
  TRSBoxPrimitive<T> = class(TObject)
    ...
  end;

  TBoxInteger = TRSBoxPrimitive<Integer>;
  TUnboxInteger = TBoxInteger;
  ...

{$else}

type
  TBoxInteger = TObject;
  TUnboxInteger = Integer;
  ...

{$endif}

implementation

{$ifdef AUTOREFCOUNT}

...

{$endif}

end.

那么你根本不需要{$IFDEF}你的AddObject()调用,只需在所有平台上无条件地使用TBoxIntegerTUnboxInteger,例如:

// look ma, no IFDEF's!
uses BoxPrimitives;

cbGender.Items.AddObject('Male', TBoxInteger(1));
cbGender.Items.AddObject('Female', TBoxInteger(0));
...
var Value: Integer;
Value := TUnboxInteger(cbGender.Items.Objects[index]);

【讨论】:

    【解决方案2】:

    根据 Dalija 的评论,答案是修改代码,使其看起来像这样:

    {$if defined(Android) and (CompilerVersion < 34)}
    uses BoxPrimitives
    {$endif}
    
    {$if defined(Android) and (CompilerVersion < 34)}
    cbGender.Items.AddObject('Male', TBoxInteger(1));
    cbGender.Items.AddObject('Female', TBoxInteger(0));
    {$else}
    cbGender.Items.AddObject('Male', TObject(1));
    cbGender.Items.AddObject('Female', TObject(0));
    {$endif}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-08
      • 2019-05-16
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多