我正在使用RAD Studio XE-5来创建Android应用程序,但最近偶然发现了一个令人费解的错误。 TStringList.AddObject引发以下异常:
Project Project3.apk raised exception class Segmentation fault (11).
我的代码就是这个
procedure TMainForm.FormCreate(Sender: TObject);
var
list: TStrings;
begin
list := TStringList.Create;
list.AddObject('Joe', TObject(1)); // This is where exception is raised
list.AddObject('Hans', TObject(2));
end;
此代码在32位Windows目标上运行完全正常,但在我的Nexus 7上运行(在调试模式下)时会引发上述异常(当我不使用TStringList.AddObject时运行正常)。如果我在没有调试的情况下运行应用程序,它就会关闭我的Nexus。
这是Delphi Android的已知问题/限制吗?是否有解决方法或推荐的方法来实现相同的结果(不仅仅是这个玩具示例,而是一般使用AddObject)?
答案 0 :(得分:4)
整个编程风格是在Delphi 7时代做事的方式。但从那时起,许多事情都发生了变化。最具体地说,移动编译器使用ARC,他们将尝试销毁字符串列表中保存的对象。这解释了你看到的错误。
另一个变化是在D2009中添加了对泛型的支持。您现在应该为此任务使用类型安全通用容器,而不是字符串列表。周围有许多,但让我们展示一个来自Generics.Collections
的内置类的例子。
您需要创建一个列表元素类型。它包含一个字符串和一个整数。
type
TMyItem = record
public
Name: string;
Age: Integer;
end;
让我们轻松制作新的方法:
function NewMyItem(const Name: string; const Age: Integer): TMyItem;
begin
Result.Name := Name;
Result.Age := Age;
end;
然后让我们列出它们:
var
List: TList<TMyItem>;
....
List := TList<TMyItem>.Create;
现在添加一些项目:
List.Add(NewMyItem('Joe', 1));
List.Add(NewMyItem('Hans', 2));
答案 1 :(得分:0)
我不知道,为什么斯蒂芬·格里恩克(Stefan Glienke)没有写评论作为答案,但这是另一个很好的答案:
请参阅此博客文章(它讨论了iOS,但同样适用于 Android): http://blogs.riversoftavg.com/index.php/2013/08/01/using-primitive-types-with-tstrings-in-ios/
建议创建一个新的包装器类,以将Integer包装到TObject中,使它们的类运算符Implicit和Explicit易于转换,并使用强制转换为此类,而不是将Integers强制转换为TObject然后返回Integer。它将所需的代码更改减至最少。