Potrzebuję skonwertować objekt do JSON no to niby nic prostszego napisałem sobie metodę Serialize
korzystającą z TJSONMarshal
i wszystko jest pięknie, działa wynik poprawny ale każde wywołanie powoduje wyciek pamięci (kilkadziesiąt nawet kilkaset KB w zależności od rozmiarów obrazka). Metoda będzie wywoływana tysiące razy podczas działania programu więc nie mogę twego zlekceważyć mimo, że po kilku godzinach męki naprawdę mam ochotę.
Mój kod odtwarzający problem wygląda tak:
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.JSON, Data.DBXJSON, Data.DBXJSONReflect, Data.DBXJSONCommon,
Vcl.StdCtrls, Vcl.Imaging.jpeg;
type
TFS = class helper for TFileStream
function Serialize: string;
end;
TTestObj = class
private
fName: string;
fImg: TFileStream;
public
property Name: string read fName write fName;
property Img: TFileStream read fImg write fImg;
function Serialize: string;
constructor Create(AName: string; AFileName: string);
destructor Destroy; override;
end;
TForm4 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
function TFS.Serialize;
var
jArray: TJSONArray;
begin
result:= '';
Self.Position:= 0;
jArray:= TDBXJSONTools.StreamToJSON(Self, 0, Self.Size);
try
if Assigned(jArray) then
result:= jArray.ToJSON;
finally
Self.Position:= 0;
jArray.Free;
end;
end;
function TTestObj.Serialize: string;
var
m: TJSONMarshal;
begin
result:= '';
m:= TJSONMarshal.Create(TJSONConverter.Create);
try
m.RegisterConverter(TTestObj, 'fImg', function(Data: TObject; Field: String): string
var
sJArray: string;
begin
sJArray:= TTestObj(Data).Img.Serialize; //zwraca jako JSON tablicę bajtów [255,216,255,224,0,16,...,185,255,217]
if Length(sJArray) > 0 then
result:= sJArray
else
//jezeli wykomentuje jak ponizej to tego zaznaczonego dużego wycieku NIE MA! Tylko jak funkcja zwróci ten długi ciąg :/
{if Length(sJArray) > 0 then
result:= sJArray
else}
result:= '[]';
end);
result:= m.Marshal(Self).ToJSON;
finally
m.Free;
end;
end;
constructor TTestObj.Create(AName: string; AFileName: string);
begin
inherited Create;
fName:= AName;
fImg:= TFileStream.Create(AFileName, fmOpenRead);
end;
destructor TTestObj.Destroy;
begin
fImg.Free;
inherited Destroy;
end;
procedure TForm4.Button1Click(Sender: TObject);
var
Test: TTestObj;
jStr: string;
begin
Test:= TTestObj.Create('TEST', 'd:\test.jpg');
try
jStr:= Test.Serialize;
Memo1.Text:= jStr;
finally
Test.Free;
end;
end;
end.
Na wyjściu w Memo ładnie dostaję to co chcę czyli:
{"type":"Unit4.TTestObj","id":1,"fields":{"fName":"TEST","fImg":"[255,216,255,224,0,16,74,70,73,70,0,1,1,1,0,96,0,96,0,0,255,219,0,67,0,2,1,1,2,1,1,2,2,2,2,2,2,2,2,3,5,3,3,3,3,3,6,4,4,3,5,7,6,7,7,7,6,7,7,8,9,11,9,8,8,10,8,7,7,10,13,10,10,11,12,12,12,12,7,9,14,15,13,12,14,11,12,12,12,255,219,0,67,1,2,2,2,3,3,3,6,3,3,6,12,8,7,8,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12...
84,201,217,165,40,201,65,217,181,207,185,255,217]"}}
Ale jak zapodam sobie raportowanie błędów to jestem w czarnej dupie
ReportMemoryLeaksOnShutdown:= DebugHook <> 0;
Ma ktoś pomysł co robię nie tak, bo pół soboty zamiast na piwie siedzę przy kompie i już nie mam pomysłów?