尝试使用TJSONObject(Delphi XE4)解析JSON文件。
解析后我想销毁TJSONObject以防止内存泄漏,但是:
procedure TfmMain.ReadIngrJSON(const fName: string);
var i: integer;
S: TStringList;
JSONObject, innerObject: TJSONObject;
innerArray: TJSONArray;
begin
S:=TStringList.Create;
try
S.LoadFromFile(fName);
JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
if Assigned(JSONObject) then
begin
SetLength(ingrArray, JSONObject.Size);
for i := 0 to JSONObject.Size-1 do
begin
ingrArray[i].id:=JSONObject.Get(i).JsonString.Value;
innerObject:=JSONObject.Get(ingrArray[i].id).JsonValue as TJSONObject;
innerArray:=innerObject.Get('en').JsonValue as TJSONArray;
ingrArray[i].name[0]:=innerArray.Get(0).Value;
ingrArray[i].units[0]:=innerArray.Get(1).Value;
innerArray:=innerObject.Get('ru').JsonValue as TJSONArray;
ingrArray[i].name[1]:=innerArray.Get(0).Value;
ingrArray[i].units[1]:=innerArray.Get(1).Value;
innerArray:=nil;
end;
innerObject.Destroy;
for i := 0 to Length(ingrArray)-1 do
listIngredients.Items.Add(ingrArray[i].name[1]);
end
else
raise Exception.Create('no JSON data');
finally
JSONObject.Destroy; //here is an error 'invalid pointer operation'
S.Free;
end;
end;
我的代码有什么问题?
答案 0 :(得分:1)
正确的模式 - 甚至内置于Delphi代码模板中
Object-var := Object-Class.Create; // or any other way to create the instance
try
// ...
finally
Object-var.Destroy;
end;
相反,您将对象创建放在try
和finally
之间的代码中间,这样可以保证:
如果在S.LoadFromFile(fName);
中发生某种异常,则会通过垃圾指针调用Destroy
。
如果在JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
中发生某种异常,则会通过垃圾指针调用Destroy
。
如果nil
是JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
的结果,则会Destroy
超过nil
指针;
总的来说,我听说DBX JSON没什么好处 - 很多人抱怨错误或工作缓慢。而且你也很难理解什么是对象的生命周期以及如何在Delphi中管理它。出于这两个原因,我认为您最好使用经过多年测试的引用计数库JSON库而不是DBX。
答案 1 :(得分:1)
您有责任免费拨打Get
的电话号码。您的责任在于您在Get
的代码中调用JSONObject
的对象。您必须删除调用innerObject.Destroy
。
您遇到无效指针操作错误的原因是JSONObject
正在尝试销毁您已销毁的对象。
如果您调用的引用恰好是Destroy
,则通常不会调用nil
。而是调用执行Free
检查的nil
,如果引用为零则跳过对Destroy
的调用。
最后,你对finally的使用是不正确的。正确的模式是:
obj := TSomeClass.Create;
try
// use obj
finally
obj.Free; // obj.Destroy is also fine in this case because obj <> nil
end;
您必须在构造函数分配给引用后立即放置try
。如果您之前使用它,那么您对Free
的调用可能会对未初始化的引用起作用。如果您之后没有立即放置,那么您可能会泄漏。
对于您的JSON对象,您可以这样写:
JSONObject := TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
if Assigned(JSONObject) then
try
....
finally
JSONObject.Free;
end;
或者你也可以这样做:
JSONObject := TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
try
if Assigned(JSONObject) then
begin
....
end;
finally
JSONObject.Free;
end;